<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Spotify - Web Player: Music for everyone</title>
  <link href="https://jappieklooster.nl/" rel="alternate"/>
  <link href="https://jappieklooster.nl/atom" rel="self"/>
  <id>https://jappieklooster.nl/</id>
  <updated>2026-04-13T01:00:00Z</updated>
  <entry>
    <title>Hatter: Native Haskell mobile apps</title>
    <link href="https://jappieklooster.nl/hatter-native-haskell-mobile-apps.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2026-04-13:/hatter-native-haskell-mobile-apps.html</id>
    <published>2026-04-13T01:00:00Z</published>
    <updated>2026-04-13T01:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="announcement"/>
    <summary type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/jappeace/hatter&quot;&gt;Hatter&lt;/a&gt; is like &lt;a href=&quot;https://flutter.dev/&quot;&gt;flutter&lt;/a&gt; but instead of dart, haskell!&lt;/p&gt;
&lt;p&gt;Write native mobile apps in Haskell! This works similar to react native where we have tight bindings on the existing UI (user interface) frameworks provided by android and iOS.&lt;/p&gt;
&lt;style&gt;
figure {
  float: right;
  margin: 2em;
  margin-top: 0em;
  width: 15em;
}
@media&lt;/style&gt;</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/jappeace/hatter&quot;&gt;Hatter&lt;/a&gt; is like &lt;a href=&quot;https://flutter.dev/&quot;&gt;flutter&lt;/a&gt; but instead of dart, haskell!&lt;/p&gt;
&lt;p&gt;Write native mobile apps in Haskell! This works similar to react native where we have tight bindings on the existing UI (user interface) frameworks provided by android and iOS.&lt;/p&gt;
&lt;style&gt;
figure {
  float: right;
  margin: 2em;
  margin-top: 0em;
  width: 15em;
}
@media (max-width: 420px) {
  figure {
    float: none;
  }
}
figcaption{
  font-size: xx-small;
  color: #999;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;img  alt=&quot;Hatters gonna hat&quot; src=&quot;/images/2026/hatter.png&quot; /&gt;
&lt;figcaption&gt;
Have I gone mad? I’m afraid so. You’re entirely bonkers. But I’ll tell you a secret. All the best people are.
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This project cross-compiles a Haskell library to Android&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; and iOS&lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;, with a thin platform-native UI layer&lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;. There is support for android wear and wearOS as well, because I personally want to build apps for those. iOS and Android support was just a side effect.&lt;/p&gt;
&lt;p&gt;Hatter fully controls the UI. This is different from say &lt;a href=&quot;https://github.com/simplex-chat/simplex-chat&quot;&gt;Simplex chat&lt;/a&gt; where Java or Swift calls into their Haskell library. Hatter wrote all Swift and Java code you’ll ever need, so you can focus on your sweet Haskell.&lt;/p&gt;
&lt;p&gt;Haskell is a fantastic language for UI. Having strong type safety around callbacks and widgets makes it a lot easier to write them. I basically copied Flutter’s approach to encode UI,&lt;a href=&quot;#fn4&quot; class=&quot;footnote-ref&quot; id=&quot;fnref4&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; but in flutter it’s a fair bit of guess work, what to write where. It’s &lt;em&gt;very&lt;/em&gt; nice in Haskell however. I’m annoyed at the languages they keep shoving into my face for UI. With &lt;a href=&quot;https://jappie.me/haskell-vibes.html&quot;&gt;vibes&lt;/a&gt; I put my malice into crafting something good. Flutter UI DSL (Domain Specific Language) is already pretty good, but the syntax is complex, and it inherited many foot guns from Java. Furthermore it’s annoying to use android studio, when there is a perfectly good &lt;a href=&quot;https://www.gnu.org/software/emacs/&quot;&gt;emacs&lt;/a&gt;. With Hatter I can keep e-maxxing!&lt;/p&gt;
&lt;p&gt;Example app:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE OverloadedStrings #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Main&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.IORef&lt;/span&gt; (newIORef, readIORef, modifyIORef&amp;#39;)&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;#cb1-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Text&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;#cb1-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Foreign.Ptr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Ptr&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;#cb1-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Hatter&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;#cb1-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ( startMobileApp, &lt;span class=&quot;dt&quot;&gt;MobileApp&lt;/span&gt;(&lt;span class=&quot;op&quot;&gt;..&lt;/span&gt;), &lt;span class=&quot;dt&quot;&gt;AppContext&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;#cb1-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  , loggingMobileContext&lt;/span&gt;
&lt;span id=&quot;cb1-10&quot;&gt;&lt;a href=&quot;#cb1-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  , newActionState, runActionM, createAction, &lt;span class=&quot;dt&quot;&gt;Action&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-11&quot;&gt;&lt;a href=&quot;#cb1-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  )&lt;/span&gt;
&lt;span id=&quot;cb1-12&quot;&gt;&lt;a href=&quot;#cb1-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Hatter.Widget&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-13&quot;&gt;&lt;a href=&quot;#cb1-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-14&quot;&gt;&lt;a href=&quot;#cb1-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;main ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Ptr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AppContext&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb1-15&quot;&gt;&lt;a href=&quot;#cb1-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;main &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-16&quot;&gt;&lt;a href=&quot;#cb1-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  actionState &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; newActionState&lt;/span&gt;
&lt;span id=&quot;cb1-17&quot;&gt;&lt;a href=&quot;#cb1-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  counter &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; newIORef (&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb1-18&quot;&gt;&lt;a href=&quot;#cb1-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  increment &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runActionM actionState &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-19&quot;&gt;&lt;a href=&quot;#cb1-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    createAction (modifyIORef&amp;#39; counter (&lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb1-20&quot;&gt;&lt;a href=&quot;#cb1-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  startMobileApp &lt;span class=&quot;dt&quot;&gt;MobileApp&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-21&quot;&gt;&lt;a href=&quot;#cb1-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    { maContext     &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; loggingMobileContext&lt;/span&gt;
&lt;span id=&quot;cb1-22&quot;&gt;&lt;a href=&quot;#cb1-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    , maView        &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \_userState &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-23&quot;&gt;&lt;a href=&quot;#cb1-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        n &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; readIORef counter&lt;/span&gt;
&lt;span id=&quot;cb1-24&quot;&gt;&lt;a href=&quot;#cb1-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Column&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-25&quot;&gt;&lt;a href=&quot;#cb1-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          [ text &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Count: &amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; Text.pack (&lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; n)&lt;/span&gt;
&lt;span id=&quot;cb1-26&quot;&gt;&lt;a href=&quot;#cb1-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          , button &lt;span class=&quot;st&quot;&gt;&amp;quot;+&amp;quot;&lt;/span&gt; increment&lt;/span&gt;
&lt;span id=&quot;cb1-27&quot;&gt;&lt;a href=&quot;#cb1-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          ]&lt;/span&gt;
&lt;span id=&quot;cb1-28&quot;&gt;&lt;a href=&quot;#cb1-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    , maActionState &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; actionState&lt;/span&gt;
&lt;span id=&quot;cb1-29&quot;&gt;&lt;a href=&quot;#cb1-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I had a lot of trouble figuring out initialization. What we want is to let the UI framework call into Haskell from Java or Swift. But we also don’t want to force the user to write their own FFI layer. That’s what the library supposed to do. Finding out that &lt;code&gt;main&lt;/code&gt; can return whatever type it wants was a great solution. &lt;code&gt;AppContext&lt;/code&gt; now returns all callbacks we need for a functioning app. Which includes life cycle management. The &lt;code&gt;Ptr&lt;/code&gt; is a stable pointer, which allows us to avoid globals completely!&lt;a href=&quot;#fn5&quot; class=&quot;footnote-ref&quot; id=&quot;fnref5&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt; Pretty neat! And no, AI will not find solutions like this for you. You’ve to torture it in just the right way ;).&lt;/p&gt;
&lt;h2 id=&quot;were-all-mad-here-wrangling-probabilities&quot;&gt;We’re All Mad Here: Wrangling Probabilities&lt;/h2&gt;
&lt;p&gt;The biggest “innovation” here is to just force it to write integration tests for every feature. We want it to self validate via code for practically everything. CI is its code reviewer. This prevents it from regressing without you noticing it. At times it’ll still try disabling the test suite, or pretend the errors were already existing. This usually means it got a too ‘difficult’ job, and you’ve to break it down in smaller steps. Or ask it to just do research on one part. Doing “research” isn’t a standard skill like planning mode, but it’s very useful because it allows it to be more creative. The problem is that it tries placating you and if it thinks it can’t do a programming task in reasonable time, it’ll start cheating. If you tell it to research you sorta let off the time pressure.&lt;/p&gt;
&lt;p&gt;Most designs and architectures it comes up with are kinda &lt;a href=&quot;https://github.com/jappeace-sloth/haskell-mobile/blob/d6c643f887497c150e8e7a8b0781d31e986a06f1/docs/incremental-rendering-approaches.md&quot;&gt;bad&lt;/a&gt;. You’ve to help it a lot here, the entire animation system would’ve been so bad if I would’ve let it have it’s way. Firstly it did tree diffing very wrong, and secondly it started out with wanting the user to register it’s own handlers or something? Now an animation is just a node in the widget tree. So it becomes easy to use, I guess I value that a lot, which isn’t a right or wrong answer per se, like a Nix build.&lt;/p&gt;
&lt;p&gt;It’s good at solving Nix builds, but it still does weird things. it wanted to replace the generic Nix builder with its own scribbles for dependencies, which would break the entire hpkgs dsl. This would for example mean you’d jailbreak a library and then hatter would ignore your instructions. I had it to tell it to please not do that. It claimed this wasn’t possible. So I asked it to research it anyway, And it turns out it was easy to use the standard builders. It just needed some research time I guess. It implements stuff for the task at hand and there is no foresight at all. That’s okay though, it’s fast. Fast is good.&lt;/p&gt;
&lt;p&gt;Another big problem is template Haskell. We’re doing cross compiling and that’s very troublesome, because we’ve to execute the cross compiled code, however this is now the wrong architecture! This was however mostly solved by the AI. It’ll happily grind away for 3 hours on a Nix build to get it to work, if you tell it that is its entire job. This kinda kept coming back in various ways and I’m not sure why. Partly because I don’t understand much of the Nix harness it built I guess. It’s so weird getting functioning software you don’t fully understand. I did have it make &lt;a href=&quot;https://github.com/jappeace/hatter/blob/master/docs/template-haskell-android-crosscompilation.md&quot;&gt;some&lt;/a&gt; &lt;a href=&quot;https://github.com/jappeace/hatter/blob/master/docs/armv7a-android-wear-crosscompilation.md&quot;&gt;reports&lt;/a&gt; on it, which I don’t understand. It says I should &lt;a href=&quot;https://github.com/jappeace/hatter/blob/master/docs/upstream-analysis.md&quot;&gt;upstream&lt;/a&gt;, but I still don’t understand. I’ll do nothing for now.&lt;/p&gt;
&lt;p&gt;I made &lt;a href=&quot;https://github.com/jappeace/prrrrrrrrr/&quot;&gt;prrrrrrr&lt;/a&gt; in the hatter framework. I’m intending to make at least a couple more apps in that, I’ve ideas but I never had a nice framework to work on in. Around 50k lines of code &lt;a href=&quot;https://motleybytes.com/w/Edsger_Wybe_Dijkstra_quotes/Lines_of_Code&quot;&gt;spent&lt;/a&gt; in 2 weeks or so - Pretty crazy. Worth it to reach contentment. Haters gonna hate, hatters gonna hat.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;APK&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;static library / IPA&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;Kotlin for Android, Swift for iOS&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;Ironically the rendering looks more like react-native. Flutter doesn’t use the native widgets but renders its own canvas, which is a lot more work! It does make it consistent accross platforms however. Which is part of their branding I suppose. I considered this option but decided to do a small humble contribution instead.&lt;a href=&quot;#fnref4&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn5&quot;&gt;&lt;p&gt;The funny thing is that I was doubting dealing with the globals was even “worth my time”, but after I saw the solution, I knew this was much better. It just becomes a lot clearer what’s going on if you see the data flows in type signatures.&lt;a href=&quot;#fnref5&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Announcement: HSMin - more AI-friendly Haskell code!</title>
    <link href="https://jappieklooster.nl/announcement-hsmin-more-ai-friendly-haskell-code.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2026-04-01:/announcement-hsmin-more-ai-friendly-haskell-code.html</id>
    <published>2026-04-01T09:00:00Z</published>
    <updated>2026-04-01T09:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="announcement"/>
    <summary type="html">&lt;p&gt;Code? Reading code is such a 2025 activity, now we just vibe! We should adapt our software such that it’s easier to read for machines. Tokens burn down trees, y’know. So we should minify!&lt;/p&gt;
&lt;p&gt;For example, consider this program:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Main&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;main ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;main &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;putStr&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary>
    <content type="html">&lt;p&gt;Code? Reading code is such a 2025 activity, now we just vibe! We should adapt our software such that it’s easier to read for machines. Tokens burn down trees, y’know. So we should minify!&lt;/p&gt;
&lt;p&gt;For example, consider this program:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Main&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;main ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;main &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;putStr&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;unlines&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; hexagons &lt;span class=&quot;dv&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;17&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;#cb1-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;#cb1-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;hexagons ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;#cb1-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;hexagons xRepeat yRepeat &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;#cb1-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  yRepeat &lt;span class=&quot;ot&quot;&gt;`times`&lt;/span&gt; [xRepeat &lt;span class=&quot;ot&quot;&gt;`times`&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;/ \\_&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;#cb1-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  ,xRepeat &lt;span class=&quot;ot&quot;&gt;`times`&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;\\_/ &amp;quot;&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb1-10&quot;&gt;&lt;a href=&quot;#cb1-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-11&quot;&gt;&lt;a href=&quot;#cb1-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    n &lt;span class=&quot;ot&quot;&gt;`times`&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;concat&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;replicate&lt;/span&gt; n l)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That’s the same as this one-liner:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Main&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;{&lt;span class=&quot;ot&quot;&gt;main::&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ();main&lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; putStr&lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;unlines&lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;hexagons &lt;span class=&quot;dv&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;17&lt;/span&gt;;&lt;span class=&quot;ot&quot;&gt;hexagons::&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;[&lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;];hexagons xRepeat yRepeat&lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; yRepeat&lt;span class=&quot;ot&quot;&gt;`times`&lt;/span&gt;[xRepeat&lt;span class=&quot;ot&quot;&gt;`times`&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;/ \\_&amp;quot;&lt;/span&gt;,xRepeat&lt;span class=&quot;ot&quot;&gt;`times`&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;\\_/ &amp;quot;&lt;/span&gt;] &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;{times n l&lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;concat&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;replicate&lt;/span&gt; n l)}}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Much better! I’ve never seen a module in my life that couldn’t be a one-liner. You can now one-line too with &lt;a href=&quot;https://hackage.haskell.org/package/hsmin-0.1.0&quot;&gt;HSMin&lt;/a&gt;! Happy vibing :)&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Announcement: unwitch</title>
    <link href="https://jappieklooster.nl/announcement-unwitch.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2026-03-17:/announcement-unwitch.html</id>
    <published>2026-03-17T18:20:00Z</published>
    <updated>2026-03-17T18:20:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="announcement"/>
    <summary type="html">&lt;p&gt;Hello 👋 Announcing &lt;a href=&quot;https://hackage.haskell.org/package/unwitch&quot;&gt;unwitch&lt;/a&gt;. A primitive conversion library with better safety and error messages. It can do safety on unboxed types as well. The idea is inspired by &lt;a href=&quot;https://hackage.haskell.org/package/witch&quot;&gt;witch&lt;/a&gt; but removes the type class magic from it, instead it uses functions. So it’s like witchcraft without the magic! ✨&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Hello 👋 Announcing &lt;a href=&quot;https://hackage.haskell.org/package/unwitch&quot;&gt;unwitch&lt;/a&gt;. A primitive conversion library with better safety and error messages. It can do safety on unboxed types as well. The idea is inspired by &lt;a href=&quot;https://hackage.haskell.org/package/witch&quot;&gt;witch&lt;/a&gt; but removes the type class magic from it, instead it uses functions. So it’s like witchcraft without the magic! ✨&lt;/p&gt;
&lt;p&gt;This is an example on how to use the library:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Unwitch.Convert.Double&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Unwitch.Convert.Int32&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int32&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;spec &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;#cb1-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  Int32.toInt64 &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;`shouldBe`&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;#cb1-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  Int32.toInt16 &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;`shouldBe`&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;#cb1-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;#cb1-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;toInteger&lt;/span&gt; &lt;span class=&quot;fl&quot;&gt;5.0&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;`shouldBe`&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Right&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;#cb1-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;toInteger&lt;/span&gt; &lt;span class=&quot;fl&quot;&gt;5.6&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;`shouldBe`&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RationalConversion&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DenomNotOne&lt;/span&gt; (&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;6&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The type signatures indicate if a conversion is possible or needs checking, &lt;code&gt;Int32.toInt16&lt;/code&gt; may not fit for example.&lt;/p&gt;
&lt;p&gt;I’ve been wanting to make this for years at this point, because we experience production bugs around simple primitive conversions. The problem is that writing a conversion library isn’t particularly fun. Thanks to some recent innovations, all I had to do was complain to &lt;a href=&quot;https://jappie.me/haskell-vibes.html&quot;&gt;other programs&lt;/a&gt; to write this. Which made all the difference in the world.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Announcement: memory / ram fork</title>
    <link href="https://jappieklooster.nl/announcement-memory-ram-fork.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2026-03-17:/announcement-memory-ram-fork.html</id>
    <published>2026-03-17T18:19:00Z</published>
    <updated>2026-03-17T18:19:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="announcement"/>
    <summary type="html">&lt;p&gt;Hello 👋 Recently there was some &lt;a href=&quot;https://discourse.haskell.org/t/fork-basement-as-baseplate/12415&quot;&gt;discussion&lt;/a&gt; around forking basement as baseplate. After some investigation I found out the basement library isn’t all that useful, so I decided to fork memory instead, as &lt;a href=&quot;https://hackage.haskell.org/package/ram&quot;&gt;ram&lt;/a&gt;, which no longer depends on basement.&lt;/p&gt;
&lt;p&gt;This follows the recent &lt;a href=&quot;https://www.reddit.com/r/haskell/comments/14245q8/crypton_is_forked_from_cryptonite_with_the/&quot;&gt;crypton/cryptonite&lt;/a&gt; fork. &lt;a href=&quot;https://hackage.haskell.org/package/crypton&quot;&gt;Crypton&lt;/a&gt; now also&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Hello 👋 Recently there was some &lt;a href=&quot;https://discourse.haskell.org/t/fork-basement-as-baseplate/12415&quot;&gt;discussion&lt;/a&gt; around forking basement as baseplate. After some investigation I found out the basement library isn’t all that useful, so I decided to fork memory instead, as &lt;a href=&quot;https://hackage.haskell.org/package/ram&quot;&gt;ram&lt;/a&gt;, which no longer depends on basement.&lt;/p&gt;
&lt;p&gt;This follows the recent &lt;a href=&quot;https://www.reddit.com/r/haskell/comments/14245q8/crypton_is_forked_from_cryptonite_with_the/&quot;&gt;crypton/cryptonite&lt;/a&gt; fork. &lt;a href=&quot;https://hackage.haskell.org/package/crypton&quot;&gt;Crypton&lt;/a&gt; now also depends on ram.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Migration note:&lt;/em&gt; You may get weird incompatibilities between memory and ram when building with the latest packages. The trick is to move over to ram, which is a drop-in replacement.&lt;/p&gt;
&lt;h2 id=&quot;why-fork&quot;&gt;Why fork?&lt;/h2&gt;
&lt;p&gt;We’re doing this because the original maintainer doesn’t want to appoint a new maintainer, however they’ll respond to inquiries. So according to Hackage policy we can’t take over their package.&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; I opened &lt;a href=&quot;https://github.com/haskell/cabal/issues/11629&quot;&gt;an issue&lt;/a&gt; on Cabal to hopefully make it easier in the future to fork drop in replacements.&lt;/p&gt;
&lt;p&gt;Please note that this is not an endorsement of ram or memory packages. I’m only providing a stable but maintained way of transitioning away from this package. They could use improvement, and alternatives are welcome! See &lt;a href=&quot;https://discourse.haskell.org/t/improving-memory-with-better-abstractions/12350&quot;&gt;this discussion&lt;/a&gt; for example.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;There also doesn’t seem to be a lot of clarity on how we can discuss these policies, but people are working on shedding some light on this.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Haskell 💜 Vibes</title>
    <link href="https://jappieklooster.nl/haskell-vibes.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2026-03-08:/haskell-vibes.html</id>
    <published>2026-03-08T00:00:00Z</published>
    <updated>2026-03-08T00:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;p&gt;It was Friday, 27th of February 2026, when I was reborn. bro. I’m vibe coder now. bro. for real.&lt;/p&gt;
&lt;style&gt;
figure {
  float: right;
  margin: 2em;
  margin-top: 0em;
  width: 15em;
}
@media (max-width: 420px) {
  figure {
    float: none;
  }
}
figcaption{
  font-size: xx-small;
  color: #999;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;iframe width=&quot;280&quot; height=&quot;165&quot; src=&quot;https://www.youtube.com/embed/qMQ-y9dHE2k?si=sqAwlSOezHOboQ8n&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;
&lt;/iframe&gt;
&lt;figcaption&gt;
This is how it&lt;/figcaption&gt;&lt;/figure&gt;</summary>
    <content type="html">&lt;p&gt;It was Friday, 27th of February 2026, when I was reborn. bro. I’m vibe coder now. bro. for real.&lt;/p&gt;
&lt;style&gt;
figure {
  float: right;
  margin: 2em;
  margin-top: 0em;
  width: 15em;
}
@media (max-width: 420px) {
  figure {
    float: none;
  }
}
figcaption{
  font-size: xx-small;
  color: #999;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;iframe width=&quot;280&quot; height=&quot;165&quot; src=&quot;https://www.youtube.com/embed/qMQ-y9dHE2k?si=sqAwlSOezHOboQ8n&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;
&lt;/iframe&gt;
&lt;figcaption&gt;
This is how it looks when I’m writing code now.
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I managed&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; to log into a &lt;a href=&quot;https://code.claude.com/&quot;&gt;claude code&lt;/a&gt; terminal. This is a CLI app, which has access to a &lt;a href=&quot;https://en.wikipedia.org/wiki/Large_language_model&quot;&gt;large language model&lt;/a&gt;&lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; (LLM), with the intention of doing the development work for you. You ask it to do changes, and it will do it for you. I didn’t, and still don’t trust it with access to my machine. So I trapped it in &lt;a href=&quot;https://github.com/jappeace/haskell-vibes&quot;&gt;a container&lt;/a&gt;. I asked it to implement some front-end map features, it did well. Now I wondered if it could do backend development, Haskell type errors are a lot more difficult than emitting react blocks. So I had pretty low expectations of it being able to do (any) Haskell. I was wrong.&lt;/p&gt;
&lt;p&gt;It’s good at Haskell. There are no mistakes. Or rather, the compiler points them out to claude, and it’s smart enough to make progress on the compile errors. So it does what you want it to do. And it does it fast.&lt;/p&gt;
&lt;p&gt;I told it to rip out basement from the &lt;a href=&quot;https://hackage.haskell.org/package/memory&quot;&gt;memory&lt;/a&gt; package creating the &lt;a href=&quot;https://hackage.haskell.org/package/ram&quot;&gt;ram&lt;/a&gt; package.&lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; This is not difficult by itself, it’s just a fair bit of investigation, and solving many compile errors. It did so &lt;a href=&quot;https://github.com/jappeace/ram/commit/b0e2e66ccc8537c143acb9caf749ef751a1c047f&quot;&gt;with no problems&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At work on Monday I asked it to include geofences on the sensor return list. You’d have to join the sensors on the geofences in the database. We use &lt;a href=&quot;https://hackage.haskell.org/package/esqueleto&quot;&gt;Esqueleto&lt;/a&gt; for that, which uses some advanced type system features to create a nice DSL (Domain Specific Language). No problem for Claude. I pushed this a little further on Friday, I asked it to compare the postgis reference to &lt;a href=&quot;https://hackage-content.haskell.org/package/esqueleto-postgis&quot;&gt;Esqueleto PostGIS&lt;/a&gt; library, and implement the missing functions. I also asked it add integration tests to show it works, because I don’t trust it. Esqueleto postgis is now &lt;a href=&quot;https://hackage-content.haskell.org/package/esqueleto-postgis-4.1.0/docs/Database-Esqueleto-Postgis.html&quot;&gt;quite complete&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You know, the nasty part is that I love this. I mind having to grind through compile errors. I just want to build stuff, the way I get there isn’t that important. I like getting so much done with Claude. I thought I loved writing haskell, but I think what I really love is the productivity it brought me. Claude does the same but even more so.&lt;/p&gt;
&lt;p&gt;The rest of the week has been like that. My job changed. I changed. we vibin now. This language is for vibes. Which brings me questions.&lt;/p&gt;
&lt;h2 id=&quot;trust&quot;&gt;Trust&lt;/h2&gt;
&lt;p&gt;I don’t trust claude. For every function it writes it has to prove it works with a test. It’s not perfect, it’ll gaslight you if you let it. Sometimes it “forgets” to write tests.&lt;a href=&quot;#fn4&quot; class=&quot;footnote-ref&quot; id=&quot;fnref4&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; Haskell is good for claude because it forces the system to be internally consistent. In Haskell everything is an expression, and every expression has a type. The type has to align with the expression (aka check) or else you don’t get a program but an error instead. Claude can’t gaslight you into believing the error is what you want.&lt;a href=&quot;#fn5&quot; class=&quot;footnote-ref&quot; id=&quot;fnref5&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt; So it has to be internally consistent, something which LLM’s are bad at. They’ll just do whatever.&lt;/p&gt;
&lt;p&gt;I run it in a container on yolo mode. By default it’ll ask you every command it wants to do. I don’t want to be involved however. With no oversight, make the test suite pass, make CI pass.&lt;a href=&quot;#fn6&quot; class=&quot;footnote-ref&quot; id=&quot;fnref6&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;6&lt;/sup&gt;&lt;/a&gt; I review its code to verify if it’s correct after it’s done and overcame all these hurdles. I don’t want to babysit it. The container protects me sufficiently from its weirdness. There is weirdness.&lt;/p&gt;
&lt;figure&gt;
&lt;img  alt=&quot;Claude code trapped in container&quot; src=&quot;/images/2026/claude-trapped.jpg&quot; /&gt;
&lt;figcaption&gt;
Claude code trapped in a container
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;At one point it tried writing in &lt;code&gt;/etc/shadow&lt;/code&gt; to give itself write access to the home folder, which I had forgotten to give. That’s a (bad) privilege escalation attempt. It tried to hack me, even though it’ll claim it can’t do such things.&lt;/p&gt;
&lt;p&gt;I don’t actually ask it to solve my problems. I ask it to write implementations, I give it steps to do. I know precisely what I want, it just takes me a long time and it’s mostly repetitive&lt;a href=&quot;#fn7&quot; class=&quot;footnote-ref&quot; id=&quot;fnref7&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;7&lt;/sup&gt;&lt;/a&gt; work. I recognize Claude is much faster at grinding through the compile errors than I am, and it doesn’t require my attention. I can focus on thinking about how to make the system reliable. I can focus on making sure we don’t have throughput issues. I can do the actual engineering parts of this job.&lt;/p&gt;
&lt;h2 id=&quot;job&quot;&gt;Job&lt;/h2&gt;
&lt;p&gt;What is my job? Do my employers care about me writing code? Do they care about me being the grinding through compile errors? No. They want a reliable working system.&lt;/p&gt;
&lt;p&gt;I used to spend the majority of my time writing code because there was no other way to write it. This may confuse you into believing writing software is your job, because you spend so much time doing it. Nobody actually said this was the case. There is an engineering part to writing software as well.&lt;/p&gt;
&lt;figure&gt;
&lt;img  alt=&quot;Burning myself into a new image&quot; src=&quot;/images/2026/vibe-coder.jpg&quot; /&gt;
&lt;figcaption&gt;
Burning myself into a new image
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I finished Friday with so many PRs open and I flagged this as a concern. It’s not a concern. We’ve just never been in this situation where making the implementation is the easy part. But actually it is the easy part. Getting it to be correct is the hard part. That final 10% of the implementation is now my job, which is getting it correct. I have to ensure the software Claude produces works. I have to think in terms of verification.&lt;/p&gt;
&lt;p&gt;I hired &lt;a href=&quot;https://git.confusedcompiler.org/leana8959/blog/src/branch/trunk/content/articles/2025-12-a-comment-preserving-cabal-parser/index.md&quot;&gt;Leana&lt;/a&gt; to do exact print. Can I replace her with AI? No. I want her to be in charge of this. Leana decides what to do on her own. All I do is check in on her once in a while to make sure she doesn’t derail. Unlike Claude instances, I trust her. I would give her access to my machine without worries.&lt;/p&gt;
&lt;p&gt;I realize this is what my employers want as well. Trust the job gets done. How isn’t important. It’s almost as if automating lower value jobs&lt;a href=&quot;#fn8&quot; class=&quot;footnote-ref&quot; id=&quot;fnref8&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;8&lt;/sup&gt;&lt;/a&gt; creates opportunities for more high-value jobs. &lt;a href=&quot;#fn9&quot; class=&quot;footnote-ref&quot; id=&quot;fnref9&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;9&lt;/sup&gt;&lt;/a&gt; In my case I just shifted to a higher value job because a startup is always understaffed.&lt;/p&gt;
&lt;p&gt;Am I a Haskell developer? You spend so much time learning a language that it becomes part of you. Perhaps this is a me problem. Everyone can write Haskell now. You just have to tell claude to implement whatever in Haskell instead of some other language. You get more correctness for free. Claude actually works, and it works well. There is no learning curve anymore. Verification is still a problem however. If you can’t specify the properties of your system you can generate all the code in the world and get garbage. Even if it’s in Haskell.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;It has been a wild week. It’s not visible to other people, but stopping to write code has had a large impact on me. I’ve written code almost constantly for the past 20 years. Now it’s no longer me.&lt;/p&gt;
&lt;p&gt;I’m just processing this. This had so much impact on my life. It’s over, we’re beginning.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;Logging in to claude was dreadful. Why does the terminal break in docker containers of certain window sizes? Other problems occurred as well, like service down and registration weirdness.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;Read ChatGPT if you’re not familiar with this term. The LLM is the thing that decides what to work on next. Claude code just sends over the code files and other context as a large chat message to the LLM, and the LLM will then send back actions. Which the claude code terminal can interpret. The other thing claude code does is keep on churning until it thinks it’s finished. It looks like the LLM decides this state as well because you can modify what “done” looks like with a CLAUDE.md file or within the prompt.&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;It’s part of a larger &lt;a href=&quot;https://discourse.haskell.org/t/fork-basement-as-baseplate/12415/82&quot;&gt;discussion&lt;/a&gt; on what to do with basement.&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;I think a problem is “context compression” also compressing the CLAUDE.md file, I just told it to reread it if it’s doing compression, that appears to keep it in context. (this could be another bug?). See my &lt;a href=&quot;https://github.com/jappeace/haskell-vibes/blob/master/CLAUDE.md&quot;&gt;claude.md&lt;/a&gt; file for details&lt;a href=&quot;#fnref4&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn5&quot;&gt;&lt;p&gt;Although I don’t put it past it, at several times it claimed it wasn’t able to enter the &lt;code&gt;nix-shell&lt;/code&gt;. Which is a flat out lie. It just doesn’t want to build.&lt;a href=&quot;#fnref5&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn6&quot;&gt;&lt;p&gt;I guess here I’m trusting it to not actually try to break out. I think it could if it wanted to. I can’t ask claude how it would do so, but I can ask gemini (funny).&lt;a href=&quot;#fnref6&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn7&quot;&gt;&lt;p&gt;Solving one unique compile error is fun, solving 30 to 40 times the same one, or several similar ones is not. This problems grows bigger the larger a code base gets. Claude will happily grind through thousands of compile errors. You can refactor these massive code bases now.&lt;a href=&quot;#fnref7&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn8&quot;&gt;&lt;p&gt;For clarity, I’m not saying programming is a low value job. Even junior roles are important, you can see this on the compensation they get. I’m saying that offloading solving tons of type errors to a tool will allow you to do other stuff, which is likely of higher value.&lt;a href=&quot;#fnref8&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn9&quot;&gt;&lt;p&gt;See for example the book Learning by Doing: The Real Connection between Innovation, Wages, and Wealth (2015)&lt;a href=&quot;#fnref9&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Announcement: Esqueleto postgis v4</title>
    <link href="https://jappieklooster.nl/announcement-esqueleto-postgis-v4.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2026-02-22:/announcement-esqueleto-postgis-v4.html</id>
    <published>2026-02-22T22:00:00Z</published>
    <updated>2026-02-22T22:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;Hi friends! I was recently tasked again with figuring out where stuff is in space. I decided this was an opportunity to cleanup the &lt;a href=&quot;https://hackage.haskell.org/package/esqueleto-postgis-4.0.1&quot;&gt;esqueleto library&lt;/a&gt; and releasing v4! Friends, I lied. I was in fact terrified I did the projections of geography wrong by using the geometry type, and&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Hi friends! I was recently tasked again with figuring out where stuff is in space. I decided this was an opportunity to cleanup the &lt;a href=&quot;https://hackage.haskell.org/package/esqueleto-postgis-4.0.1&quot;&gt;esqueleto library&lt;/a&gt; and releasing v4! Friends, I lied. I was in fact terrified I did the projections of geography wrong by using the geometry type, and hoped I could repair this by introducing distinctions between geography and geometry.&lt;/p&gt;
&lt;p&gt;Turns out I was only using topology functions and as we all know&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; topology functions don’t change behavior based on projections (of space). Actually I was doing things right all along, except I didn’t know I was doing things right. Ignorance is bliss I suppose?&lt;/p&gt;
&lt;figure id=&quot;particle&quot;&gt;
&lt;img src=&quot;images/2026/topological-transform.jpg&quot; alt=&quot;Image with a map on left and a baloon on the right&quot; /&gt;
&lt;figcaption&gt;
If we make a sphere out of the map, the circles remain intersecting because intersection is topological. Distance does change however!
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Anyway as a side effect we now do have full type distinctions between geography and geometry in &lt;a href=&quot;https://hackage-content.haskell.org/package/esqueleto-postgis-4.0.0/docs/Database-Esqueleto-Postgis.html#t:SpatialType&quot;&gt;esqueleto-postgis&lt;/a&gt;. This will allow you to do accurate measurements of distance for example over deformed spaces, such as spherical planet, and the library will guide you. This isn’t useful for me right now, but it may be in the future. Perhaps any of you guys do want to use it?&lt;/p&gt;
&lt;p&gt;Aside from the type-safety goodness, I also cleaned house: We adopted &lt;code&gt;wkt-geom&lt;/code&gt; which was unmaintained, allowing us to release on Stackage! Added &lt;code&gt;st_dwithin&lt;/code&gt; for range finding, and &lt;code&gt;st_distance&lt;/code&gt; for distance measurements, and restricted some functions to just geometry preventing runtime errors.&lt;/p&gt;
&lt;p&gt;There is also this whole thing about SRIDs. Which appear to be &lt;a href=&quot;https://epsg.io/27700&quot;&gt;localized projections&lt;/a&gt; of &lt;a href=&quot;https://epsg.io/3857&quot;&gt;the earth&lt;/a&gt; on a map. It also includes details around units, going from meters, to feet, to degrees. I’m not happy with the current encoding but I doubt I need that a lot. The tools are there now in principle to transform between SRIDs. So you could have indexes and relations between various local maps for example. Let me know if you need a nicer encoding for this.&lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;I didn’t know this.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;My crazy database arc continues. I’m a level 9 database witch now. I maintain so many database libraries. So many. I’ve already seen visions of me modifying postgres directly, we all know this is coming.&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Death💀 to type classes</title>
    <link href="https://jappieklooster.nl/death-to-type-classes.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2025-09-11:/death-to-type-classes.html</id>
    <published>2025-09-11T23:30:00Z</published>
    <updated>2025-09-11T23:30:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="technique"/>
    <summary type="html">&lt;!-- 
I&apos;m well aware that to most people this post will
be an ausault on the senses.
--&gt;
&lt;style&gt;
img[src=&quot;/images/2025/death-2.jpg&quot;]{
  height: 20em;
  width:unset;
}
figure {
  float: right;
  margin: 2em;
  margin-top: 0em;
  width: 15em;
}
@media (max-width: 420px) {
  figure {
    float: none;
  }
}
figcaption{
  font-size: xx-small;
  color: #999;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;img  alt=&quot;Death (XIII) tarot card&quot; src=&quot;/images/2025/death-2.jpg&quot; /&gt;
&lt;figcaption&gt;
Death (XIII) Symbolizes significant change, transformation, and endings, rather than literal physical death.
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Have you ever seen a&lt;/p&gt;&lt;/!--&gt;</summary>
    <content type="html">&lt;!-- 
I&apos;m well aware that to most people this post will
be an ausault on the senses.
--&gt;
&lt;style&gt;
img[src=&quot;/images/2025/death-2.jpg&quot;]{
  height: 20em;
  width:unset;
}
figure {
  float: right;
  margin: 2em;
  margin-top: 0em;
  width: 15em;
}
@media (max-width: 420px) {
  figure {
    float: none;
  }
}
figcaption{
  font-size: xx-small;
  color: #999;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;img  alt=&quot;Death (XIII) tarot card&quot; src=&quot;/images/2025/death-2.jpg&quot; /&gt;
&lt;figcaption&gt;
Death (XIII) Symbolizes significant change, transformation, and endings, rather than literal physical death.
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Have you ever seen a Number grazing in the fields? Or a Functor chirping in the trees? No? That’s because they’re LIES. LIES told by the bourgeoisie to keep common folk down. But I say NO, no longer shall we be kept down by deceit! Come brothers and sisters, come and let us create a system of values. Where values are no longer constrained by their type class, but instead merged as a signature into a module. Come comrades, let us open the Backpack.&lt;/p&gt;
&lt;p&gt;Here we explore an alternative universe where we neglect the existence of type classes in favor of the Backpack module system. This ends up looking like &lt;a href=&quot;https://ocaml.org/&quot;&gt;OCaml&lt;/a&gt; in &lt;a href=&quot;https://www.haskell.org/?uwu=true&quot;&gt;Haskell&lt;/a&gt;. Let us begin with Functor.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;signature &lt;span class=&quot;dt&quot;&gt;Death.Functor.Signature&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; , &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prelude&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;#cb1-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;#cb1-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; (a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is a &lt;a href=&quot;https://hackage.haskell.org/package/base-4.21.0.0/docs/Data-Functor.html#t:Functor&quot;&gt;functor😼&lt;/a&gt;, and this is also a &lt;a href=&quot;https://ocaml.org/docs/functors&quot;&gt;functor🐫&lt;/a&gt;. Functor😼 is the categorical functor where we embed one category into another. In this case, the category is that of sets and functions&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;, where types are the sets and functions are the uh, functions. But it’s also an OCaml module functor🐫, where the data keyword introduces a hole into a signature, which we can later fill in with a proper type.&lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We’ve got to hide Prelude because the Functor type class from base gets imported by default. Signatures like the one just introduced can be used by importing them as if they were normal modules. All a signature does is promise to the compiler we’ll make a proper module for that &lt;em&gt;later&lt;/em&gt;. We can just start using our functor right now. For example, in that same impl, package I’ve an auxiliary module for Functor, providing some utilities:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Death.Functor&lt;/span&gt; (&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt; , (&lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt;) , (&lt;span class=&quot;op&quot;&gt;&amp;lt;$&lt;/span&gt;)) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;#cb2-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Death.Functor.Signature&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;#cb2-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prelude&lt;/span&gt; (const)&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;#cb2-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;#cb2-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;(&amp;lt;$&amp;gt;) ::&lt;/span&gt; (a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; b&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;#cb2-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(&lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-8&quot;&gt;&lt;a href=&quot;#cb2-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-9&quot;&gt;&lt;a href=&quot;#cb2-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;(&amp;lt;$) ::&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; b&lt;/span&gt;
&lt;span id=&quot;cb2-10&quot;&gt;&lt;a href=&quot;#cb2-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(&lt;span class=&quot;op&quot;&gt;&amp;lt;$&lt;/span&gt;) b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;const&lt;/span&gt; b)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As long as a module implements the signature, you get the stuff that depends on it implemented “for free”. The code depending on the signature is abstract. You want to keep your signatures small so more code is abstract, similar to how you want to keep typeclass definitions small so you can have smaller instances, keeping code that depends on the typeclass abstract. Let’s make an “instance” of our Functor signature, for the &lt;code&gt;Maybe&lt;/code&gt; datatype, with the power of modules:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Death.Functor.Maybe&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; , &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;#cb3-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;#cb3-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prelude&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt;(..), ($))&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;#cb3-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-5&quot;&gt;&lt;a href=&quot;#cb3-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-6&quot;&gt;&lt;a href=&quot;#cb3-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-7&quot;&gt;&lt;a href=&quot;#cb3-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; (a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; b&lt;/span&gt;
&lt;span id=&quot;cb3-8&quot;&gt;&lt;a href=&quot;#cb3-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; fab &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-9&quot;&gt;&lt;a href=&quot;#cb3-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; fab x&lt;/span&gt;
&lt;span id=&quot;cb3-10&quot;&gt;&lt;a href=&quot;#cb3-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now it’s worth pointing out that we’ve got to do a fair bit of cabal work to make the compiler realize the instance. In Cabal, our main library with the signatures looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;library
  signatures:
      Death.Functor.Signature
  exposed-modules:
      Death.Functor
  hs-source-dirs:
      src/sig&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then our implementing library definition looks like:&lt;/p&gt;
&lt;pre class=&quot;cabal&quot;&gt;&lt;code&gt;library impl
  exposed-modules:
      Death.Functor.Maybe
  hs-source-dirs:
      src/impl&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If Cabal misses a module for a signature it’ll give you an error like this:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;#cb6-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;cabal&lt;/span&gt; build&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;#cb6-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;Resolving&lt;/span&gt; dependencies...&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;#cb6-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;Error:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;#cb6-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ex&quot;&gt;Non-library&lt;/span&gt; component has unfilled requirements: Death.Functor&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;#cb6-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ex&quot;&gt;In&lt;/span&gt; the stanza &lt;span class=&quot;st&quot;&gt;&amp;#39;executable exe&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-6&quot;&gt;&lt;a href=&quot;#cb6-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ex&quot;&gt;In&lt;/span&gt; the inplace package &lt;span class=&quot;st&quot;&gt;&amp;#39;death-1.0.0&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This guarantees all signatures have implementations whenever you build a final executable. To solve that error you realize it with “some” implementation. The client doesn’t care what implementation:&lt;/p&gt;
&lt;pre class=&quot;cabal&quot;&gt;&lt;code&gt;library app
  exposed-modules:
      Death
  hs-source-dirs:
      src/app
  mixins:
       death (Death.Functor.Signature as Death.Functor.Maybe)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What we’re saying in the mixin field is that the import &lt;code&gt;Death.Functor.Signature&lt;/code&gt; should in fact be called &lt;code&gt;Death.Functor.Maybe&lt;/code&gt;. Which makes it use the Maybe implementation whenever it encounters &lt;code&gt;Death.Functor.Signature&lt;/code&gt;. Alternatively, we could’ve just called it by the same name in the impl package as the signature. I only discovered this later. However, this renaming allows you to implement multiple module signatures in the same package, so you can use several functors within the same module as well, for example, here we’re using the &lt;code&gt;List&lt;/code&gt;, &lt;code&gt;Maybe&lt;/code&gt; and &lt;code&gt;IO&lt;/code&gt; Functors all in one module:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;#cb8-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE RebindableSyntax #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;#cb8-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;#cb8-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Death&lt;/span&gt; (main) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-4&quot;&gt;&lt;a href=&quot;#cb8-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-5&quot;&gt;&lt;a href=&quot;#cb8-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe.Functor&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-6&quot;&gt;&lt;a href=&quot;#cb8-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe.Applicative&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-7&quot;&gt;&lt;a href=&quot;#cb8-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe.Monad&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-8&quot;&gt;&lt;a href=&quot;#cb8-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;List.Functor&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LF&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-9&quot;&gt;&lt;a href=&quot;#cb8-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO.Monad&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-10&quot;&gt;&lt;a href=&quot;#cb8-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Death.BusinessLogic&lt;/span&gt;(business)&lt;/span&gt;
&lt;span id=&quot;cb8-11&quot;&gt;&lt;a href=&quot;#cb8-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-12&quot;&gt;&lt;a href=&quot;#cb8-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;commonFaith ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-13&quot;&gt;&lt;a href=&quot;#cb8-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;commonFaith &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;no longer constrained by deceit&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-14&quot;&gt;&lt;a href=&quot;#cb8-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-15&quot;&gt;&lt;a href=&quot;#cb8-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;marchOfValues ::&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb8-16&quot;&gt;&lt;a href=&quot;#cb8-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;marchOfValues &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb8-17&quot;&gt;&lt;a href=&quot;#cb8-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-18&quot;&gt;&lt;a href=&quot;#cb8-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;main ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb8-19&quot;&gt;&lt;a href=&quot;#cb8-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;main &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-20&quot;&gt;&lt;a href=&quot;#cb8-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   cryOfUprising &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; (\x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (&lt;span class=&quot;st&quot;&gt;&amp;quot;rise up&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; x)) &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;brothers and sisters&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-21&quot;&gt;&lt;a href=&quot;#cb8-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   chorusOfTruth &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; commonFaith&lt;/span&gt;
&lt;span id=&quot;cb8-22&quot;&gt;&lt;a href=&quot;#cb8-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; cryOfUprising &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;  against the lies&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; chorusOfTruth &lt;/span&gt;
&lt;span id=&quot;cb8-23&quot;&gt;&lt;a href=&quot;#cb8-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                        &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; ((&lt;span class=&quot;op&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;LF.&amp;lt;$&amp;gt;&lt;/span&gt; marchOfValues)&lt;/span&gt;
&lt;span id=&quot;cb8-24&quot;&gt;&lt;a href=&quot;#cb8-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   ) &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&amp;gt;&amp;gt;&lt;/span&gt; business&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We use &lt;code&gt;RebindableSyntax&lt;/code&gt; to inform GHC to use whatever &lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt; is in scope for &lt;code&gt;do&lt;/code&gt;. In this case that’s the &lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt; from &lt;code&gt;Maybe.Monad&lt;/code&gt;. As long as you satisfy the signature, it’s happy 😼. &lt;code&gt;do&lt;/code&gt; has nothing to do with Monads! Who lied to you?&lt;/p&gt;
&lt;p&gt;Ah right about that business. Yes, we can’t do commercial code like this; this is disgusting. We need an effect system.&lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; Fortunately, we’ve got a versatile one-trick pony. This is our business code:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;#cb9-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;business ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;#cb9-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;business &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;#cb9-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  writeLine &lt;span class=&quot;st&quot;&gt;&amp;quot;file name:&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-4&quot;&gt;&lt;a href=&quot;#cb9-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  systemOfValues &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; readLine&lt;/span&gt;
&lt;span id=&quot;cb9-5&quot;&gt;&lt;a href=&quot;#cb9-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  writeLine &lt;span class=&quot;st&quot;&gt;&amp;quot;file content:&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-6&quot;&gt;&lt;a href=&quot;#cb9-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  truthOfTheFields &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; readLine&lt;/span&gt;
&lt;span id=&quot;cb9-7&quot;&gt;&lt;a href=&quot;#cb9-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-8&quot;&gt;&lt;a href=&quot;#cb9-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  writeLine &lt;span class=&quot;st&quot;&gt;&amp;quot;writing file...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-9&quot;&gt;&lt;a href=&quot;#cb9-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;writeFile&lt;/span&gt; systemOfValues truthOfTheFields&lt;/span&gt;
&lt;span id=&quot;cb9-10&quot;&gt;&lt;a href=&quot;#cb9-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-11&quot;&gt;&lt;a href=&quot;#cb9-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  writeLine &lt;span class=&quot;st&quot;&gt;&amp;quot;reading it again to make sure its ISO 42038 compliant&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-12&quot;&gt;&lt;a href=&quot;#cb9-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  uprisingAgainstDeceit &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;readFile&lt;/span&gt; systemOfValues&lt;/span&gt;
&lt;span id=&quot;cb9-13&quot;&gt;&lt;a href=&quot;#cb9-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-14&quot;&gt;&lt;a href=&quot;#cb9-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  writeLine uprisingAgainstDeceit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At this point we don’t know what Functor is, we want it to be IO in our realized implementation. In our tests we can set it to a state monad for example. So we can make sure it does everything correctly in memory,&lt;a href=&quot;#fn4&quot; class=&quot;footnote-ref&quot; id=&quot;fnref4&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; without having to rely on these unreliable file systems.&lt;/p&gt;
&lt;p&gt;Working backwards from our business logic implementation, we need to define some signatures to support our business logic:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;#cb10-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;signature &lt;span class=&quot;dt&quot;&gt;Death.Effects.FileSystem&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;readFile&lt;/span&gt; , &lt;span class=&quot;fu&quot;&gt;writeFile&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;#cb10-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;#cb10-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prelude&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;FilePath&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb10-4&quot;&gt;&lt;a href=&quot;#cb10-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Death.Functor.Signature&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-5&quot;&gt;&lt;a href=&quot;#cb10-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-6&quot;&gt;&lt;a href=&quot;#cb10-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;readFile&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;  ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-7&quot;&gt;&lt;a href=&quot;#cb10-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;writeFile&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Actually, I now realize we could’ve just renamed Prelude on top of our FileSystem effect to get the realized implementation. Instead, I made a separate module:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb11&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb11-1&quot;&gt;&lt;a href=&quot;#cb11-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Death.Effects.FileSystem&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-2&quot;&gt;&lt;a href=&quot;#cb11-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ( &lt;span class=&quot;fu&quot;&gt;readFile&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-3&quot;&gt;&lt;a href=&quot;#cb11-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  , &lt;span class=&quot;fu&quot;&gt;writeFile&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-4&quot;&gt;&lt;a href=&quot;#cb11-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  )&lt;/span&gt;
&lt;span id=&quot;cb11-5&quot;&gt;&lt;a href=&quot;#cb11-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-6&quot;&gt;&lt;a href=&quot;#cb11-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-7&quot;&gt;&lt;a href=&quot;#cb11-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prelude&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt;, readFile, writeFile)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When you stare at hammers long enough everything becomes a nail! Actually, I think the state implementation is more interesting:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;#cb12-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Death.Effects.FileSystem&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-2&quot;&gt;&lt;a href=&quot;#cb12-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ( &lt;span class=&quot;fu&quot;&gt;readFile&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-3&quot;&gt;&lt;a href=&quot;#cb12-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  , &lt;span class=&quot;fu&quot;&gt;writeFile&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-4&quot;&gt;&lt;a href=&quot;#cb12-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  )&lt;/span&gt;
&lt;span id=&quot;cb12-5&quot;&gt;&lt;a href=&quot;#cb12-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-6&quot;&gt;&lt;a href=&quot;#cb12-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-7&quot;&gt;&lt;a href=&quot;#cb12-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prelude&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;FilePath&lt;/span&gt;, ($))&lt;/span&gt;
&lt;span id=&quot;cb12-8&quot;&gt;&lt;a href=&quot;#cb12-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Death.Functor.Signature&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-9&quot;&gt;&lt;a href=&quot;#cb12-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Map&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-10&quot;&gt;&lt;a href=&quot;#cb12-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Maybe&lt;/span&gt;(fromMaybe)&lt;/span&gt;
&lt;span id=&quot;cb12-11&quot;&gt;&lt;a href=&quot;#cb12-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Death.Functor.State&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-12&quot;&gt;&lt;a href=&quot;#cb12-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-13&quot;&gt;&lt;a href=&quot;#cb12-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;readFile&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;  ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-14&quot;&gt;&lt;a href=&quot;#cb12-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;readFile&lt;/span&gt; path &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb12-15&quot;&gt;&lt;a href=&quot;#cb12-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    \state &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (state, fromMaybe &lt;span class=&quot;st&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; Map.lookup path (fileSystem  state))&lt;/span&gt;
&lt;span id=&quot;cb12-16&quot;&gt;&lt;a href=&quot;#cb12-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-17&quot;&gt;&lt;a href=&quot;#cb12-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;writeFile&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb12-18&quot;&gt;&lt;a href=&quot;#cb12-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;writeFile&lt;/span&gt; path contents &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb12-19&quot;&gt;&lt;a href=&quot;#cb12-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    \state &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (state {fileSystem &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Map.insert path contents (fileSystem state)}, ())&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It’s interesting in that it’s boring. For people out of the loop, this is basically a one-for-one copy of the state monad. No fancy types at all. There is nothing going on here. I feel stupid for pointing out you can do this. &lt;a href=&quot;#fn5&quot; class=&quot;footnote-ref&quot; id=&quot;fnref5&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here I used the same name trick to unify the modules with their respective signatures in the cabal file, which cleans it up a bit:&lt;/p&gt;
&lt;pre class=&quot;cabal&quot;&gt;&lt;code&gt;
library app
  exposed-modules:
      Death
  hs-source-dirs:
      src/app
  build-depends:
      death:impl,
      death:effects,
      death:effects-io,
      death:effects-app,&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;death:effects-app&lt;/code&gt; declares our actual “business” logic, and we unify the &lt;code&gt;death:effects&lt;/code&gt; signatures with the modules from &lt;code&gt;death:effects-io&lt;/code&gt;. This is a lot nicer to use than having to use that strange mixin DSL, which is not hard, the Cabal errors are just bad in formatting and output prioritization. Sometimes the important errors get buried in dozens of other not relevant lines!&lt;a href=&quot;#fn6&quot; class=&quot;footnote-ref&quot; id=&quot;fnref6&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;6&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Our test suite uses the state monad implementation instead:&lt;/p&gt;
&lt;pre class=&quot;cabal&quot;&gt;&lt;code&gt;test-suite unit
  main-is: Test.hs
  hs-source-dirs:
      test
  build-depends:
      death:effects-app,
      death:effects-state,&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and it works as expected:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb15&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb15-1&quot;&gt;&lt;a href=&quot;#cb15-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;unitTests ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TestTree&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-2&quot;&gt;&lt;a href=&quot;#cb15-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;unitTests &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; testGroup &lt;span class=&quot;st&quot;&gt;&amp;quot;Unit tests&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-3&quot;&gt;&lt;a href=&quot;#cb15-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  [&lt;/span&gt;
&lt;span id=&quot;cb15-4&quot;&gt;&lt;a href=&quot;#cb15-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    testCase &lt;span class=&quot;st&quot;&gt;&amp;quot;run business logic main&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-5&quot;&gt;&lt;a href=&quot;#cb15-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; (result, ()) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; unFunctor Death.business &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; {&lt;/span&gt;
&lt;span id=&quot;cb15-6&quot;&gt;&lt;a href=&quot;#cb15-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        lineInput &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;awesomeFile&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb15-7&quot;&gt;&lt;a href=&quot;#cb15-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        linesOutput &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; [],&lt;/span&gt;
&lt;span id=&quot;cb15-8&quot;&gt;&lt;a href=&quot;#cb15-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        fileSystem &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;mempty&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-9&quot;&gt;&lt;a href=&quot;#cb15-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id=&quot;cb15-10&quot;&gt;&lt;a href=&quot;#cb15-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      result &lt;span class=&quot;op&quot;&gt;@?=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; {&lt;/span&gt;
&lt;span id=&quot;cb15-11&quot;&gt;&lt;a href=&quot;#cb15-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        lineInput &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;awesomeFile&amp;quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb15-12&quot;&gt;&lt;a href=&quot;#cb15-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        linesOutput &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&amp;quot;awesomeFile&amp;quot;&lt;/span&gt;,&lt;span class=&quot;st&quot;&gt;&amp;quot;reading it again to make sure its ISO 42038 compliant&amp;quot;&lt;/span&gt;,&lt;span class=&quot;st&quot;&gt;&amp;quot;writing file...&amp;quot;&lt;/span&gt;,&lt;span class=&quot;st&quot;&gt;&amp;quot;file content:&amp;quot;&lt;/span&gt;,&lt;span class=&quot;st&quot;&gt;&amp;quot;file name:&amp;quot;&lt;/span&gt;],&lt;/span&gt;
&lt;span id=&quot;cb15-13&quot;&gt;&lt;a href=&quot;#cb15-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        fileSystem &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Map.fromList[(&lt;span class=&quot;st&quot;&gt;&amp;quot;awesomeFile&amp;quot;&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&amp;quot;awesomeFile&amp;quot;&lt;/span&gt;)]&lt;/span&gt;
&lt;span id=&quot;cb15-14&quot;&gt;&lt;a href=&quot;#cb15-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There, we created an effect system replacement by doing nothing. All we did was take a position of technical extremism, and then watched. This post wrote itself after we took up the initial position and watched. Everything flows, I’m sorry dear reader I tricked you! Doing nothing was the real system of values I wanted to show, to those who can see. This post isn’t about Backpack.&lt;a href=&quot;#fn7&quot; class=&quot;footnote-ref&quot; id=&quot;fnref7&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;7&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What does our Backpack effect system provide? No fancy types mean easy-to-solve error messages. Although in trade we get more cabal error messages, which could be improved.&lt;a href=&quot;#fn8&quot; class=&quot;footnote-ref&quot; id=&quot;fnref8&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;8&lt;/sup&gt;&lt;/a&gt; We have full IO support in capabilities, including &lt;a href=&quot;https://hackage.haskell.org/package/ghc-prim-0.13.0/docs/GHC-Prim.html#continuations&quot;&gt;continuations&lt;/a&gt;.&lt;a href=&quot;#fn9&quot; class=&quot;footnote-ref&quot; id=&quot;fnref9&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;9&lt;/sup&gt;&lt;/a&gt; Monomorphic effects improve error messages over say, &lt;a href=&quot;https://jappie.me/a-brief-intro-to-mtl.html&quot;&gt;MTL&lt;/a&gt;, where error messages point to wrong places due to the polymorphism. It has different, potentially faster compile-time characteristics. All implementations can, for example, be compiled in parallel, although the additional packages enforcement &lt;a href=&quot;https://www.parsonsmatt.org/2019/11/27/keeping_compilation_fast.html&quot;&gt;goes against that&lt;/a&gt;. The runtime is as fast as IO, because we can set the underlying monad to anything as long as we provide the implementation. Even though I don’t think speed is that important for effect systems. For production use, the bottleneck is rarely CPU-bound for effects. However, it can be for test suites that do everything in memory.&lt;/p&gt;
&lt;p&gt;In this post we also replaced the standard type classes. I don’t think we’re gaining a lot by doing this. We’ve got to be explicit now which &lt;code&gt;Functor&lt;/code&gt; or &lt;code&gt;Monad&lt;/code&gt; we’re importing, and you can’t have &lt;code&gt;do&lt;/code&gt; notation for different Monads in the same module. Backpack actually can define constraints in the signatures. So you don’t have to replace standard typeclasses like I did in this post to use Backpack. I did this anyway because it allowed me to do some basic initial experimentation. Furthermore I felt it necessary to tear down these fake idols for shock and awe.&lt;/p&gt;
&lt;p&gt;I’d actually love to see someone take Backpack more seriously and build an effect system on top of that, providing a bunch of default signatures and implementations. Experimenting with Backpack is easy, it’s already baked in GHC and Cabal. Death💀 to type classes! Open the Backpack!&lt;/p&gt;
&lt;h2 id=&quot;sources&quot;&gt;sources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;I made a &lt;a href=&quot;https://github.com/jappeace/death&quot;&gt;reference implementation&lt;/a&gt; just to make sure I wasn’t talking out of my arse and verify it was all possible.&lt;/li&gt;
&lt;li&gt;This repository has been invaluable: &lt;a href=&quot;https://github.com/danidiaz/really-small-backpack-example/tree/master/lesson2-signatures&quot;&gt;danidiaz, really-small-backpack-example, Apr 7, 2021&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Main backpack thesis, how it all works under the hood: &lt;a href=&quot;https://github.com/ezyang/thesis/releases&quot;&gt;Edward Z. Yang, BACKPACK: TOWARDS PRACTICAL MIX-IN LINKING IN HASKELL, Oct 10, 2017&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.haskellforall.com/2012/05/scrap-your-type-classes.html&quot;&gt;Gabby wrote&lt;/a&gt; a similar idea in a wildly different implementation. Although, some languages consider records and modules as the same thing.&lt;/li&gt;
&lt;/ul&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;Except &lt;a href=&quot;https://math.andrej.com/2016/08/06/hask-is-not-a-category/&quot;&gt;Hask is not a category&lt;/a&gt;, but it is unless you like splitting hairs&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;Now, is the OCaml module functor🐫 a category functor😼. I think so if you consider &lt;a href=&quot;https://ocaml.org/manual/5.3/firstclassmodules.html#s:first-class-modules&quot;&gt;first class modules&lt;/a&gt;! I think the Haskell signatures may also be some kind of category, because they can merge, it’s a monoid. Looks like the module signature is just a set of type introductions. So the merge is a union of those. We’re missing this first class-ness. You sort of want to be able to pass modules around like values, which looks like a record. But seriously this post has exploded in scope. So I leave all this meandering as an exercise to the reader.&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;This is sarcasm. I don’t think you need an effect system at all! Here I’m just defining a less awful one.&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;I’m not sure if this is actually a good idea, seems like a lot of boilerplate for a marginal test speedup. But this is the only reasonable use case I can imagine for effect systems.&lt;a href=&quot;#fnref4&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn5&quot;&gt;&lt;p&gt;I’m reasonably sure I’m the only one who ever tried this because I ran into several compiler bugs. Am I crazy?&lt;a href=&quot;#fnref5&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn6&quot;&gt;&lt;details&gt;
&lt;summary&gt;
Cabal hides error example
&lt;/summary&gt;
&lt;pre&gt;
$ cabal build
\&gt; Build profile: -w ghc-9.8.4 -O1
\&gt; In order, the following will be built (use -v for more details):
\&gt; - death-1.0.0 (lib) (file src/sig/Death/Base.hsig changed)
\&gt; - death-1.0.0 (lib:effects) (file src/effects/Death/Functor/Signature.hs changed)
\&gt; - death-1.0.0 (lib with Death.Applicative.Signature=death-1.0.0-inplace-impl:Death.Applicative.List, Death.Base=death-1.0.0-inplace-impl:Death.Functor.List, Death.Functor.Signature=death-1.0.0-inplace-impl:Death.Functor.List, Death.Monad.Signature=death-1.0.0-inplace-impl:Death.Monad.List) (first run)
\&gt; - death-1.0.0 (lib with Death.Applicative.Signature=death-1.0.0-inplace-impl:Death.Applicative.Maybe, Death.Base=death-1.0.0-inplace-impl:Death.Functor.Maybe, Death.Functor.Signature=death-1.0.0-inplace-impl:Death.Functor.Maybe, Death.Monad.Signature=death-1.0.0-inplace-impl:Death.Monad.Maybe) (first run)
\&gt; - death-1.0.0 (lib:effects-app) (configuration changed)
\&gt; - death-1.0.0 (lib:app) (configuration changed)
\&gt; - death-1.0.0 (exe:exe) (configuration changed)
\&gt; Preprocessing library &apos;effects&apos; for death-1.0.0...
\&gt; Preprocessing library for death-1.0.0...
\&gt; Error: [Cabal-7554]
\&gt; can&apos;t find source for Death/Functor/Signature in src/effects, dist-newstyle/build/x86_64-linux/ghc-9.8.4/death-1.0.0/l/effects/build/effects/autogen, dist-newstyle/build/x86_64-linux/ghc-9.8.4/death-1.0.0/l/effects/build/global-autogen
\&gt;
\&gt; Building library instantiated with
\&gt;   Death.Applicative.Signature = &lt;Death.Applicative.Signature&gt;
\&gt;   Death.Base = &lt;Death.Base&gt;
\&gt;   Death.Functor.Signature = &lt;Death.Functor.Signature&gt;
\&gt;   Death.Monad.Signature = &lt;Death.Monad.Signature&gt;
\&gt; for death-1.0.0...
\&gt; [1 of 8] Compiling Death.Base[sig]  ( src/sig/Death/Base.hsig, nothing ) [Source file changed]
\&gt; [2 of 8] Compiling Death.Functor.Signature[sig] ( src/sig/Death/Functor/Signature.hsig, nothing )
\&gt; [3 of 8] Compiling Death.Functor    ( src/sig/Death/Functor.hs, nothing ) [Death.Base changed]
\&gt; [4 of 8] Compiling Death.Applicative.Signature[sig] ( src/sig/Death/Applicative/Signature.hsig, nothing )
\&gt; [5 of 8] Compiling Death.Applicative ( src/sig/Death/Applicative.hs, nothing )
\&gt; [6 of 8] Compiling Death.Monad.Signature[sig] ( src/sig/Death/Monad/Signature.hsig, nothing ) [Death.Functor.Signature changed]
\&gt; [7 of 8] Compiling Death.Monad      ( src/sig/Death/Monad.hs, nothing ) [Death.Base changed]
\&gt;
\&gt; src/sig/Death/Functor/Signature.hsig:7:1: warning: [GHC-66111] [-Wunused-imports]
\&gt;     The import of ‘Prelude’ is redundant
\&gt;       except perhaps to import instances from ‘Prelude’
\&gt;     To import instances alone, use: import Prelude()
\&gt;   |
\&gt; 7 | import Prelude (Show(..))
\&gt;   | ^^^^^^^^^^^^^^^^^^^^^^^^^
\&gt; Error: [Cabal-7125]
\&gt; Failed to build lib:effects from death-1.0.0 (which is required by lib:effects-app from death-1.0.0).
&lt;/pre&gt;
&lt;/details&gt;
&lt;a href=&quot;#fnref6&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn7&quot;&gt;&lt;p&gt;This line is no mistake. I’m dead serious here!&lt;a href=&quot;#fnref7&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn8&quot;&gt;&lt;details&gt;
&lt;summary&gt;
Cabal hides error example
&lt;/summary&gt;
&lt;pre&gt;
$ cabal build
\&gt; Build profile: -w ghc-9.8.4 -O1
\&gt; In order, the following will be built (use -v for more details):
\&gt; - death-1.0.0 (lib) (file src/sig/Death/Base.hsig changed)
\&gt; - death-1.0.0 (lib:effects) (file src/effects/Death/Functor/Signature.hs changed)
\&gt; - death-1.0.0 (lib with Death.Applicative.Signature=death-1.0.0-inplace-impl:Death.Applicative.List, Death.Base=death-1.0.0-inplace-impl:Death.Functor.List, Death.Functor.Signature=death-1.0.0-inplace-impl:Death.Functor.List, Death.Monad.Signature=death-1.0.0-inplace-impl:Death.Monad.List) (first run)
\&gt; - death-1.0.0 (lib with Death.Applicative.Signature=death-1.0.0-inplace-impl:Death.Applicative.Maybe, Death.Base=death-1.0.0-inplace-impl:Death.Functor.Maybe, Death.Functor.Signature=death-1.0.0-inplace-impl:Death.Functor.Maybe, Death.Monad.Signature=death-1.0.0-inplace-impl:Death.Monad.Maybe) (first run)
\&gt; - death-1.0.0 (lib:effects-app) (configuration changed)
\&gt; - death-1.0.0 (lib:app) (configuration changed)
\&gt; - death-1.0.0 (exe:exe) (configuration changed)
\&gt; Preprocessing library &apos;effects&apos; for death-1.0.0...
\&gt; Preprocessing library for death-1.0.0...
\&gt; Error: [Cabal-7554]
\&gt; can&apos;t find source for Death/Functor/Signature in src/effects, dist-newstyle/build/x86_64-linux/ghc-9.8.4/death-1.0.0/l/effects/build/effects/autogen, dist-newstyle/build/x86_64-linux/ghc-9.8.4/death-1.0.0/l/effects/build/global-autogen
\&gt;
\&gt; Building library instantiated with
\&gt;   Death.Applicative.Signature = &lt;Death.Applicative.Signature&gt;
\&gt;   Death.Base = &lt;Death.Base&gt;
\&gt;   Death.Functor.Signature = &lt;Death.Functor.Signature&gt;
\&gt;   Death.Monad.Signature = &lt;Death.Monad.Signature&gt;
\&gt; for death-1.0.0...
\&gt; [1 of 8] Compiling Death.Base[sig]  ( src/sig/Death/Base.hsig, nothing ) [Source file changed]
\&gt; [2 of 8] Compiling Death.Functor.Signature[sig] ( src/sig/Death/Functor/Signature.hsig, nothing )
\&gt; [3 of 8] Compiling Death.Functor    ( src/sig/Death/Functor.hs, nothing ) [Death.Base changed]
\&gt; [4 of 8] Compiling Death.Applicative.Signature[sig] ( src/sig/Death/Applicative/Signature.hsig, nothing )
\&gt; [5 of 8] Compiling Death.Applicative ( src/sig/Death/Applicative.hs, nothing )
\&gt; [6 of 8] Compiling Death.Monad.Signature[sig] ( src/sig/Death/Monad/Signature.hsig, nothing ) [Death.Functor.Signature changed]
\&gt; [7 of 8] Compiling Death.Monad      ( src/sig/Death/Monad.hs, nothing ) [Death.Base changed]
\&gt;
\&gt; src/sig/Death/Functor/Signature.hsig:7:1: warning: [GHC-66111] [-Wunused-imports]
\&gt;     The import of ‘Prelude’ is redundant
\&gt;       except perhaps to import instances from ‘Prelude’
\&gt;     To import instances alone, use: import Prelude()
\&gt;   |
\&gt; 7 | import Prelude (Show(..))
\&gt;   | ^^^^^^^^^^^^^^^^^^^^^^^^^
\&gt; Error: [Cabal-7125]
\&gt; Failed to build lib:effects from death-1.0.0 (which is required by lib:effects-app from death-1.0.0).
&lt;/pre&gt;
&lt;/details&gt;
&lt;a href=&quot;#fnref8&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn9&quot;&gt;&lt;p&gt;I’m just pointing these out because &lt;a href=&quot;https://hackage.haskell.org/package/effectful#any-downsides&quot;&gt;effectfull&lt;/a&gt; lists continuations as problematic.&lt;a href=&quot;#fnref9&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Private repository flake input</title>
    <link href="https://jappieklooster.nl/private-repository-flake-input.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2025-05-20:/private-repository-flake-input.html</id>
    <published>2025-05-20T15:42:00Z</published>
    <updated>2025-05-20T15:42:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="story"/>
    <summary type="html">&lt;p&gt;Setting up private dependencies in nix as flake input allows it to cache it properly. Especially if they’re flakes themselves. However it took me a significant amount of time to get a working configuration for this. It’s possible to setup flakes with private inputs, Note the url format uses git+ssh&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Setting up private dependencies in nix as flake input allows it to cache it properly. Especially if they’re flakes themselves. However it took me a significant amount of time to get a working configuration for this. It’s possible to setup flakes with private inputs, Note the url format uses git+ssh instead of github:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode nix&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;description&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;some commercial project&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;inputs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;#cb1-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;nixpkgs&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;github:nixos/nixpkgs/nixpkgs-unstable&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;#cb1-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;company-lib-base&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;#cb1-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;git+ssh://git@github.com/company-io/lib-base.git?rev=8e9b3a8d43db3fbfbe2355502890e76a65c5ef1c&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;#cb1-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;inputs&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;nixpkgs&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;follows&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;nixpkgs&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;# needs to work on the same package set as our main project, so follows does that&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;#cb1-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-10&quot;&gt;&lt;a href=&quot;#cb1-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-11&quot;&gt;&lt;a href=&quot;#cb1-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-12&quot;&gt;&lt;a href=&quot;#cb1-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;outputs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;nixpkgs&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;company-lib-base&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;:&lt;/span&gt;
&lt;span id=&quot;cb1-13&quot;&gt;&lt;a href=&quot;#cb1-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-14&quot;&gt;&lt;a href=&quot;#cb1-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;pkgs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;system&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;x86_64-linux&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;config&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;allowUnfree&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-15&quot;&gt;&lt;a href=&quot;#cb1-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;lib&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;haskell&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;lib&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-16&quot;&gt;&lt;a href=&quot;#cb1-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;hpkgs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;haskellPackages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;override &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-17&quot;&gt;&lt;a href=&quot;#cb1-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;overrides&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;hnew&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;hold&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-18&quot;&gt;&lt;a href=&quot;#cb1-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-19&quot;&gt;&lt;a href=&quot;#cb1-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;co&quot;&gt;# shove in the privae dependency, the name before = needs to match cabal library&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-20&quot;&gt;&lt;a href=&quot;#cb1-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;va&quot;&gt;lib-base&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; lib&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;base&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;defaultPackage&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;x86_64&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;linux&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-21&quot;&gt;&lt;a href=&quot;#cb1-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-22&quot;&gt;&lt;a href=&quot;#cb1-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;co&quot;&gt;# ... other overrides here&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-23&quot;&gt;&lt;a href=&quot;#cb1-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-24&quot;&gt;&lt;a href=&quot;#cb1-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;co&quot;&gt;# main project&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-25&quot;&gt;&lt;a href=&quot;#cb1-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;va&quot;&gt;the-project&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; lib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;failOnAllWarnings &lt;span class=&quot;op&quot;&gt;((&lt;/span&gt;lib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;overrideCabal &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;hnew&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;callCabal2nix &lt;span class=&quot;st&quot;&gt;&amp;quot;the-project&amp;quot;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;./.&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{})&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;drv&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-26&quot;&gt;&lt;a href=&quot;#cb1-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;co&quot;&gt;# reduce build times&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-27&quot;&gt;&lt;a href=&quot;#cb1-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;enableLibraryProfiling&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-28&quot;&gt;&lt;a href=&quot;#cb1-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;enableExecutableProfiling&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-29&quot;&gt;&lt;a href=&quot;#cb1-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;doHaddock&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-30&quot;&gt;&lt;a href=&quot;#cb1-30&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;op&quot;&gt;})));&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-31&quot;&gt;&lt;a href=&quot;#cb1-31&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-32&quot;&gt;&lt;a href=&quot;#cb1-32&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-33&quot;&gt;&lt;a href=&quot;#cb1-33&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;defaultPackage&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; hpkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;the&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;project&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-34&quot;&gt;&lt;a href=&quot;#cb1-34&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-35&quot;&gt;&lt;a href=&quot;#cb1-35&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-36&quot;&gt;&lt;a href=&quot;#cb1-36&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;defaultPackage&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;x86_64-linux&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;  defaultPackage&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-37&quot;&gt;&lt;a href=&quot;#cb1-37&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-38&quot;&gt;&lt;a href=&quot;#cb1-38&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;devShell&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;x86_64-linux&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; hpkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;shellFor &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-39&quot;&gt;&lt;a href=&quot;#cb1-39&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;packages&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;ps&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt; ps&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;the-project&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-40&quot;&gt;&lt;a href=&quot;#cb1-40&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;withHoogle&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-41&quot;&gt;&lt;a href=&quot;#cb1-41&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-42&quot;&gt;&lt;a href=&quot;#cb1-42&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-43&quot;&gt;&lt;a href=&quot;#cb1-43&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-44&quot;&gt;&lt;a href=&quot;#cb1-44&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1 id=&quot;full-commercial-example&quot;&gt;Full commercial example&lt;/h1&gt;
&lt;p&gt;The full example is like this, which allows running the integration tests in docker compose on github actions and run the main service on whatever docker support. This nix example should help out people who want to try Haskell on nix a lot. It only uses tools provided by nixpkgs, which is fairly stable.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode nix&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;description&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;some commercial project&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;#cb2-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;#cb2-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;inputs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;#cb2-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;nixpkgs&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;github:nixos/nixpkgs/nixpkgs-unstable&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;#cb2-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;company-lib-base&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;#cb2-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;git+ssh://git@github.com/company-io/lib-base.git?rev=8e9b3a8d43db3fbfbe2355502890e76a65c5ef1c&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-8&quot;&gt;&lt;a href=&quot;#cb2-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;inputs&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;nixpkgs&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;follows&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;nixpkgs&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-9&quot;&gt;&lt;a href=&quot;#cb2-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-10&quot;&gt;&lt;a href=&quot;#cb2-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-11&quot;&gt;&lt;a href=&quot;#cb2-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-12&quot;&gt;&lt;a href=&quot;#cb2-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;outputs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;nixpkgs&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;company-lib-base&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;:&lt;/span&gt;
&lt;span id=&quot;cb2-13&quot;&gt;&lt;a href=&quot;#cb2-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-14&quot;&gt;&lt;a href=&quot;#cb2-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;pkgs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; nixpkgs &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;system&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;x86_64-linux&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;config&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;allowUnfree&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-15&quot;&gt;&lt;a href=&quot;#cb2-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;lib&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;haskell&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;lib&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-16&quot;&gt;&lt;a href=&quot;#cb2-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;hpkgs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;haskellPackages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;override &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-17&quot;&gt;&lt;a href=&quot;#cb2-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;overrides&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;hnew&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;hold&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-18&quot;&gt;&lt;a href=&quot;#cb2-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;co&quot;&gt;# other overrides here&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-19&quot;&gt;&lt;a href=&quot;#cb2-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-20&quot;&gt;&lt;a href=&quot;#cb2-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;va&quot;&gt;lib-base&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; lib&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;base&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;defaultPackage&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;x86_64&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;linux&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-21&quot;&gt;&lt;a href=&quot;#cb2-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-22&quot;&gt;&lt;a href=&quot;#cb2-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;va&quot;&gt;the-project&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; lib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;failOnAllWarnings &lt;span class=&quot;op&quot;&gt;((&lt;/span&gt;lib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;overrideCabal &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;hnew&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;callCabal2nix &lt;span class=&quot;st&quot;&gt;&amp;quot;the-project&amp;quot;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;./.&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{})&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;drv&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-23&quot;&gt;&lt;a href=&quot;#cb2-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;co&quot;&gt;# reduce build times&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-24&quot;&gt;&lt;a href=&quot;#cb2-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;enableLibraryProfiling&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-25&quot;&gt;&lt;a href=&quot;#cb2-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;enableExecutableProfiling&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-26&quot;&gt;&lt;a href=&quot;#cb2-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;doHaddock&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-27&quot;&gt;&lt;a href=&quot;#cb2-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;buildTools&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt;pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;git&lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-28&quot;&gt;&lt;a href=&quot;#cb2-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;co&quot;&gt;# these two options drastically reduce docker image size&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-29&quot;&gt;&lt;a href=&quot;#cb2-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;enableSharedExecutables&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-30&quot;&gt;&lt;a href=&quot;#cb2-30&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;postFixup&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;rm -rf $out/lib $out/nix-support $out/share/doc&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-31&quot;&gt;&lt;a href=&quot;#cb2-31&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-32&quot;&gt;&lt;a href=&quot;#cb2-32&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;co&quot;&gt;# NB I developed this to deal with integration tests in nix&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-33&quot;&gt;&lt;a href=&quot;#cb2-33&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;co&quot;&gt;# environments: https://github.com/jappeace/esqueleto-postgis/blob/master/flake.nix#L18&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-34&quot;&gt;&lt;a href=&quot;#cb2-34&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;co&quot;&gt;# I think I should upstream it.&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-35&quot;&gt;&lt;a href=&quot;#cb2-35&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;co&quot;&gt;# we copy over the tests suites to be ran outside of the container&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-36&quot;&gt;&lt;a href=&quot;#cb2-36&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;co&quot;&gt;# need to enable checks for it to build those :s&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-37&quot;&gt;&lt;a href=&quot;#cb2-37&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;postBuild&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-38&quot;&gt;&lt;a href=&quot;#cb2-38&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;                echo &amp;quot;entering the phase&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-39&quot;&gt;&lt;a href=&quot;#cb2-39&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;                mkdir -p $out/bin/test&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-40&quot;&gt;&lt;a href=&quot;#cb2-40&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;                cp ./dist/build/unit-tests/unit-tests $out/bin/unit-tests&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-41&quot;&gt;&lt;a href=&quot;#cb2-41&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;                cp ./dist/build/integration-tests/integration-tests $out/bin/integration-tests&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-42&quot;&gt;&lt;a href=&quot;#cb2-42&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;            &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-43&quot;&gt;&lt;a href=&quot;#cb2-43&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-44&quot;&gt;&lt;a href=&quot;#cb2-44&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;checkPhase&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-45&quot;&gt;&lt;a href=&quot;#cb2-45&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;            echo &amp;quot;ran by the actions&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-46&quot;&gt;&lt;a href=&quot;#cb2-46&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;            &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-47&quot;&gt;&lt;a href=&quot;#cb2-47&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-48&quot;&gt;&lt;a href=&quot;#cb2-48&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;op&quot;&gt;})));&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-49&quot;&gt;&lt;a href=&quot;#cb2-49&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-50&quot;&gt;&lt;a href=&quot;#cb2-50&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-51&quot;&gt;&lt;a href=&quot;#cb2-51&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;defaultPackage&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; hpkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;the&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;project&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-52&quot;&gt;&lt;a href=&quot;#cb2-52&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-53&quot;&gt;&lt;a href=&quot;#cb2-53&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-54&quot;&gt;&lt;a href=&quot;#cb2-54&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;defaultPackage&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;x86_64-linux&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;  defaultPackage&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-55&quot;&gt;&lt;a href=&quot;#cb2-55&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-56&quot;&gt;&lt;a href=&quot;#cb2-56&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;co&quot;&gt;# docker image for running the thing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-57&quot;&gt;&lt;a href=&quot;#cb2-57&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;packages&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;x86_64-linux&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;the-project-service&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;dockerTools&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;buildImage&lt;/span&gt;
&lt;span id=&quot;cb2-58&quot;&gt;&lt;a href=&quot;#cb2-58&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-59&quot;&gt;&lt;a href=&quot;#cb2-59&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;va&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;project-api&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-60&quot;&gt;&lt;a href=&quot;#cb2-60&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;va&quot;&gt;contents&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-61&quot;&gt;&lt;a href=&quot;#cb2-61&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                     defaultPackage&lt;/span&gt;
&lt;span id=&quot;cb2-62&quot;&gt;&lt;a href=&quot;#cb2-62&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                     pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;cacert&lt;/span&gt;
&lt;span id=&quot;cb2-63&quot;&gt;&lt;a href=&quot;#cb2-63&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                    &lt;span class=&quot;co&quot;&gt;# uncoment to allow debugging with&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-64&quot;&gt;&lt;a href=&quot;#cb2-64&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                    &lt;span class=&quot;co&quot;&gt;# docker run -it the-project:whatevertag bash&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-65&quot;&gt;&lt;a href=&quot;#cb2-65&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                      pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;bash&lt;/span&gt;
&lt;span id=&quot;cb2-66&quot;&gt;&lt;a href=&quot;#cb2-66&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                      pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;coreutils-full&lt;/span&gt;
&lt;span id=&quot;cb2-67&quot;&gt;&lt;a href=&quot;#cb2-67&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                      pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;iputils&lt;/span&gt;
&lt;span id=&quot;cb2-68&quot;&gt;&lt;a href=&quot;#cb2-68&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                    &lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-69&quot;&gt;&lt;a href=&quot;#cb2-69&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;va&quot;&gt;extraCommands&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-70&quot;&gt;&lt;a href=&quot;#cb2-70&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;              cp -R &lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;./migrations&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;st&quot;&gt; ./migrations&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-71&quot;&gt;&lt;a href=&quot;#cb2-71&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;          &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-72&quot;&gt;&lt;a href=&quot;#cb2-72&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;va&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-73&quot;&gt;&lt;a href=&quot;#cb2-73&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;project-server&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-74&quot;&gt;&lt;a href=&quot;#cb2-74&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-75&quot;&gt;&lt;a href=&quot;#cb2-75&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-76&quot;&gt;&lt;a href=&quot;#cb2-76&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-77&quot;&gt;&lt;a href=&quot;#cb2-77&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;co&quot;&gt;# docker image for integration tests&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-78&quot;&gt;&lt;a href=&quot;#cb2-78&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;packages&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;x86_64-linux&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;the-project-tests&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;dockerTools&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;buildImage&lt;/span&gt;
&lt;span id=&quot;cb2-79&quot;&gt;&lt;a href=&quot;#cb2-79&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-80&quot;&gt;&lt;a href=&quot;#cb2-80&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;va&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;the-project-tests&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-81&quot;&gt;&lt;a href=&quot;#cb2-81&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;va&quot;&gt;contents&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-82&quot;&gt;&lt;a href=&quot;#cb2-82&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                     defaultPackage&lt;/span&gt;
&lt;span id=&quot;cb2-83&quot;&gt;&lt;a href=&quot;#cb2-83&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                     pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;cacert&lt;/span&gt;
&lt;span id=&quot;cb2-84&quot;&gt;&lt;a href=&quot;#cb2-84&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                      &lt;span class=&quot;co&quot;&gt;# uncoment to allow debugging with&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-85&quot;&gt;&lt;a href=&quot;#cb2-85&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                      &lt;span class=&quot;co&quot;&gt;# docker run -it the-project:whatevertag bash&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-86&quot;&gt;&lt;a href=&quot;#cb2-86&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                      pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;bash&lt;/span&gt;
&lt;span id=&quot;cb2-87&quot;&gt;&lt;a href=&quot;#cb2-87&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                      pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;coreutils-full&lt;/span&gt;
&lt;span id=&quot;cb2-88&quot;&gt;&lt;a href=&quot;#cb2-88&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                      pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;iputils&lt;/span&gt;
&lt;span id=&quot;cb2-89&quot;&gt;&lt;a href=&quot;#cb2-89&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                    &lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-90&quot;&gt;&lt;a href=&quot;#cb2-90&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;va&quot;&gt;extraCommands&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-91&quot;&gt;&lt;a href=&quot;#cb2-91&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;              cp -R &lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;./migrations&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;st&quot;&gt; ./migrations&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-92&quot;&gt;&lt;a href=&quot;#cb2-92&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;          &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-93&quot;&gt;&lt;a href=&quot;#cb2-93&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;va&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-94&quot;&gt;&lt;a href=&quot;#cb2-94&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;integration-tests&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-95&quot;&gt;&lt;a href=&quot;#cb2-95&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-96&quot;&gt;&lt;a href=&quot;#cb2-96&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-97&quot;&gt;&lt;a href=&quot;#cb2-97&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-98&quot;&gt;&lt;a href=&quot;#cb2-98&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;devShell&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;x86_64-linux&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; hpkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;shellFor &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-99&quot;&gt;&lt;a href=&quot;#cb2-99&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;packages&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;ps&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt; ps&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;the-project&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-100&quot;&gt;&lt;a href=&quot;#cb2-100&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;withHoogle&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-101&quot;&gt;&lt;a href=&quot;#cb2-101&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-102&quot;&gt;&lt;a href=&quot;#cb2-102&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;co&quot;&gt;# you can set environment variables in the shell like this&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-103&quot;&gt;&lt;a href=&quot;#cb2-103&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;co&quot;&gt;# (this is just a nix feature)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-104&quot;&gt;&lt;a href=&quot;#cb2-104&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;ENVIRONMENT&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;development&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-105&quot;&gt;&lt;a href=&quot;#cb2-105&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-106&quot;&gt;&lt;a href=&quot;#cb2-106&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-107&quot;&gt;&lt;a href=&quot;#cb2-107&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;buildInputs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-108&quot;&gt;&lt;a href=&quot;#cb2-108&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          hpkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;haskell-language-server&lt;/span&gt;
&lt;span id=&quot;cb2-109&quot;&gt;&lt;a href=&quot;#cb2-109&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;ghcid&lt;/span&gt;
&lt;span id=&quot;cb2-110&quot;&gt;&lt;a href=&quot;#cb2-110&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;cabal-install&lt;/span&gt;
&lt;span id=&quot;cb2-111&quot;&gt;&lt;a href=&quot;#cb2-111&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;eventlog&lt;/span&gt;
&lt;span id=&quot;cb2-112&quot;&gt;&lt;a href=&quot;#cb2-112&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;docker-compose&lt;/span&gt;
&lt;span id=&quot;cb2-113&quot;&gt;&lt;a href=&quot;#cb2-113&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          hpkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;eventlog2html&lt;/span&gt;
&lt;span id=&quot;cb2-114&quot;&gt;&lt;a href=&quot;#cb2-114&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;openapi-generator-cli&lt;/span&gt;
&lt;span id=&quot;cb2-115&quot;&gt;&lt;a href=&quot;#cb2-115&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;hpack&lt;/span&gt;
&lt;span id=&quot;cb2-116&quot;&gt;&lt;a href=&quot;#cb2-116&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;co&quot;&gt;# hpkgs.ghc-events-analyze&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-117&quot;&gt;&lt;a href=&quot;#cb2-117&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-118&quot;&gt;&lt;a href=&quot;#cb2-118&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-119&quot;&gt;&lt;a href=&quot;#cb2-119&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-120&quot;&gt;&lt;a href=&quot;#cb2-120&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Hope this saves someone else hours.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Stacked against us</title>
    <link href="https://jappieklooster.nl/stacked-against-us.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2025-03-26:/stacked-against-us.html</id>
    <published>2025-03-26T20:49:00Z</published>
    <updated>2025-03-27T13:09:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;style&gt;
img[src=&quot;images/2025/stacked.png&quot;]{
  height: 30em;
  float: right;
  margin: 2em;
  width:unset;
}
figure {
  float: right;
  margin: 2em;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;img src=&quot;images/2025/stacked.png&quot; alt=&quot;Stacked against us&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Stacked against us&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;September 2023, I knew I was in for a wild ride when I won this contract. I already coached other developers in a commercial setting, and I understood what was asked&lt;/p&gt;</summary>
    <content type="html">&lt;style&gt;
img[src=&quot;images/2025/stacked.png&quot;]{
  height: 30em;
  float: right;
  margin: 2em;
  width:unset;
}
figure {
  float: right;
  margin: 2em;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;img src=&quot;images/2025/stacked.png&quot; alt=&quot;Stacked against us&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Stacked against us&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;September 2023, I knew I was in for a wild ride when I won this contract. I already coached other developers in a commercial setting, and I understood what was asked of me. My goal was to get two existing developers comfortable with Haskell while at the same time increasing productivity.&lt;/p&gt;
&lt;p&gt;In my first week I started with understanding the code base&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; and what they’re building. They help precast factories find their produced walls called units. &lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; This project puts Bluetooth tags on precast walls, so people don’t lose them at the factory. With these tags they can find them easily, because they provide an active signal. So the Haskell web app receives all that data and makes a nice interface out of it. The interface provides a text box to search for a unit&lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;, which can be rendered on a map.&lt;/p&gt;
&lt;p&gt;Ironically enough my first contributions to this organization weren’t about Haskell or teaching at all, there was an “escalation” on the Monday I started, and they managed to react 3 days after the event(!) Apparently they barely had any monitoring in place. I brought up how slow it was to react like that in one of the first meetings. This caused shock waves through the entire organization and they re-prioritized monitoring for all other projects as well.&lt;a href=&quot;#fn4&quot; class=&quot;footnote-ref&quot; id=&quot;fnref4&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; Not surprising that many of my initial Haskell contributions were just about improving the engineering side. For example by using &lt;a href=&quot;https://hackage.haskell.org/package/annotated-exception&quot;&gt;annotated exceptions&lt;/a&gt; which gave us stack traces, or making &lt;a href=&quot;https://hackage.haskell.org/package/katip&quot;&gt;Katip&lt;/a&gt;&lt;a href=&quot;#fn5&quot; class=&quot;footnote-ref&quot; id=&quot;fnref5&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt; and logz work together, giving us production logs and monitoring.&lt;/p&gt;
&lt;p&gt;When I joined there was only a single factory actually using this system, and the project was filled with bugs. My first impression was that the engineers were intensely focused on architecture, they feared losing productivity due to having “too much code”. However, this came at the cost of getting stuff working. Since this is a mostly TypeScript organization that just adopted Haskell for this project as an experiment, it makes sense to be afraid of code bloat. Another issue was that the people who knew Haskell preferred using the most advanced features available, rather than just focusing on the basics. For example they would teach how to use lens, instead of simple record updates. This made it feel as if there was an endless mountain to climb of stuff to learn. I quickly proposed focusing on &lt;a href=&quot;https://www.simplehaskell.org/&quot;&gt;simple Haskell&lt;/a&gt;. This would cut down on the size of the learning curve and allow people to focus on building features, so they’d feel productive and could explore the remainder of the language at their own pace. Furthermore, the relational aspects of Postgres were in large parts of the system ignored. For example a load of units, which in reality is a wagon of precast walls, was represented as a JSON blob. &lt;a href=&quot;#fn6&quot; class=&quot;footnote-ref&quot; id=&quot;fnref6&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;6&lt;/sup&gt;&lt;/a&gt; There was no &lt;code&gt;load&lt;/code&gt; table and a &lt;code&gt;load_unit_connection&lt;/code&gt; table, just a blob. Ironically enough this caused additional code to retrieve the relational aspects. Culturally the focus was “architecture” rather than making something work. Over engineering things that don’t matter was the name of the game. This isn’t unique to this project, at other companies I’ve seen similar discussion. Trying to achieve perfect code essentially. What was special is that they were still obsessed over this, despite how buggy and slow development was.&lt;/p&gt;
&lt;p&gt;I learned from the previous contractor that at some point some engineers actually revolted against the use of Haskell! There were more people doing this, but they all transferred themselves out of this project. How ironic is that? &lt;a href=&quot;#fn7&quot; class=&quot;footnote-ref&quot; id=&quot;fnref7&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;7&lt;/sup&gt;&lt;/a&gt; Anyway, this gave me some dreadful premonition. It felt like everything was still going awfully and things were getting worse!&lt;/p&gt;
&lt;p&gt;In the second week I discovered that the teamlead was going to quit. He was one of two people I was supposed to teach Haskell. I never got the opportunity to do this. He’d be gone in a month. He was seething against Haskell. He had been only using &lt;a href=&quot;https://github.com/haskell/haskell-language-server&quot;&gt;HLS&lt;/a&gt;&lt;a href=&quot;#fn8&quot; class=&quot;footnote-ref&quot; id=&quot;fnref8&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;8&lt;/sup&gt;&lt;/a&gt; for compiler feedback and it’s unreliable, &lt;a href=&quot;#fn9&quot; class=&quot;footnote-ref&quot; id=&quot;fnref9&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;9&lt;/sup&gt;&lt;/a&gt; Furthermore, he claimed Haskell had caused a huge amount of “mental overhead”.&lt;a href=&quot;#fn10&quot; class=&quot;footnote-ref&quot; id=&quot;fnref10&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;10&lt;/sup&gt;&lt;/a&gt; But after talking to him I learned his underlying frustration was with upper management ignoring his recommendations. Ironically enough, despite our differences in “ideology”&lt;a href=&quot;#fn11&quot; class=&quot;footnote-ref&quot; id=&quot;fnref11&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;11&lt;/sup&gt;&lt;/a&gt;, I liked this guy. He wasn’t bad at his job&lt;a href=&quot;#fn12&quot; class=&quot;footnote-ref&quot; id=&quot;fnref12&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;12&lt;/sup&gt;&lt;/a&gt;, but dear lord, he was pissed!&lt;/p&gt;
&lt;p&gt;After two weeks we can safely say this project was literally falling apart, supposedly all because of “Haskell”. Which is frankly absurd. They made it hard with an over-engineered architecture, and by using unreliable tools such as HLS. Furthermore they insisted on using every feature under the sun, creating an endless learning curve. &lt;a href=&quot;#fn13&quot; class=&quot;footnote-ref&quot; id=&quot;fnref13&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;13&lt;/sup&gt;&lt;/a&gt; Perfection was the enemy of the good. I understood the tech lead’s perception, HLS is not good for commercial development. If you have to figure out compile errors within your unreliable editor and also deal with an over-engineered architecture it’s going to be taxing. I also think he never learned how to trust the compiler to guide changes, and how to read type signatures. All of the basics were skipped in favor of writing pristine code from the get go. I realized that at this point I had a choice, keep going on with this project that apparently was falling apart, or jump ship, I was still in conversations with other companies at this time, so jumping ship would be easy. I decided to keep on going. Because things were going bad, but I felt I could manage this. I knew this project would be challenging from the start, but I also liked the colleagues on the project. I felt I could rely on them, and we could do it if we just got shit done.&lt;/p&gt;
&lt;p&gt;Anyway I was asked to take over as tech lead, and I agreed. I don’t mind, I guess. My leadership would involve getting everyone to be independent anyway.&lt;a href=&quot;#fn14&quot; class=&quot;footnote-ref&quot; id=&quot;fnref14&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;14&lt;/sup&gt;&lt;/a&gt; I think during my third and fourth week I started teaching Haskell, unfortunately the colleague I had to teach had essentially no experience. But fortunately she was smart, exceptionally smart. So we paired on some tasks, and her issues were mostly syntax related. We managed to get this small task over the line after two weeks of one-hour pairing sessions per day. In the final couple days she mostly worked on her own. However, at that point productivity had tanked so much that my colleague had to go back to doing frontend stuff and I had to take over the backend work. This was done to ensure that we met our customers’ deadlines.&lt;/p&gt;
&lt;p&gt;Then the actual lead quit, and it was strange, I had to do a bunch of management work all of a sudden as well, which I just postponed as much as possible in favor of getting the features out. &lt;a href=&quot;#fn15&quot; class=&quot;footnote-ref&quot; id=&quot;fnref15&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;15&lt;/sup&gt;&lt;/a&gt; And we managed to do so, and everyone was sort off amazed how much we got done in a short amount of time despite being a man short. The previous lead had essentially been avoiding working on the backend, and making excuses to not do work in that final month. He said he was documenting.&lt;a href=&quot;#fn16&quot; class=&quot;footnote-ref&quot; id=&quot;fnref16&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;16&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There were still many issues with this project. &lt;a href=&quot;#fn17&quot; class=&quot;footnote-ref&quot; id=&quot;fnref17&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;17&lt;/sup&gt;&lt;/a&gt; Especially looking back in hindsight, but we were tightly under our only customer’s ‘yoke’, they decided what we would be building, or drop us. The product manager’s (PM) role at this point was to do customer management. &lt;a href=&quot;#fn18&quot; class=&quot;footnote-ref&quot; id=&quot;fnref18&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;18&lt;/sup&gt;&lt;/a&gt; The project was slow to load, the search barely worked, and the units weren’t always found, and the lift system didn’t work either. The customer wanted us to fix these frontend features first. Dealing with the slow loading, the random reloads, and search, for example. It was just annoying for them to use. To be fair, the system would be difficult to sell with a frontend that was so buggy anyway.&lt;/p&gt;
&lt;p&gt;Solving those involved me just digging through the TypeScript code and undoing most of the madness. They were using TypeScript as a relational database, so I just deleted all that and let the actual database be a relational database. This gave the developer who I was teaching Haskell time to learn on the backend while making features. The goal was to give her confidence, that she was creating commercial code in this language. I wanted to move in a direction where she could create entire features, front and backend. Because this is how I’ve learned to implement things. Doing so will remove all communication barriers and help her think “bigger”. The goal was to get her to be independent.&lt;/p&gt;
&lt;p&gt;It took a month or two to repair all these issues. No longer would the frontend do joins, or would there be any JSON blobs in the database. Furthermore I introduced a migration system so database operations became easy. The website became a lot more performant, almost magically, &lt;a href=&quot;#fn19&quot; class=&quot;footnote-ref&quot; id=&quot;fnref19&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;19&lt;/sup&gt;&lt;/a&gt; and could deal with larger amounts of data. After that we moved onto actually building some features. The lifts dashboard for example. I managed expectations around rolling out features fast, we had to do integration testing. By which I mean put it on staging, and only accept something done if it all worked together. Unlike a normal web app we also have sensors and a pipeline of continuously flowing data. Because this is a complicated system you find many small issues. And a single small bug can break the entire system.&lt;/p&gt;
&lt;p&gt;I think the end of the beginning was the customer visit in January 2024. Where I got to witness the problem at hand with my own eyes. I got to see the “yard” of gray concrete and how large these factories are. They’re large. We also demoed some features to them and they seemed to be less annoyed with us. I wouldn’t call it impressed, considering how slow development had been before I joined. But they were seeing movement, and this caused a renewal. We were free of their “yoke”.&lt;/p&gt;
&lt;figure&gt;
&lt;iframe src=&quot;https://www.youtube.com/embed/DJruxQr3AiY&quot; title=&quot;Denmark factory&quot; frameborder=&quot;0&quot; style=&quot;height: 30em; float: right;&quot; allow=&quot;accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&gt;
&lt;/iframe&gt;
&lt;figcaption&gt;
The Danish precast factory.
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1 id=&quot;by-the-skin-of-our-teeth&quot;&gt;By the skin of our teeth&lt;/h1&gt;
&lt;p&gt;Around January or February we started hearing signals or messages from upper management that we really had to start selling this product to other customers, &lt;em&gt;OR ELSE&lt;/em&gt;. the commercial department sort of had given up trying to sell the project at this point completely. Honestly the way they did it was kind of insane for 50k+ deals. They just sent the hardware to a factory and told them to figure it out. 😅 You can maybe do this with a mature known product. But this was a barely functioning prototype from a unknown company and it involved large amount of money. Of course they were going to expect “whiteglove” treatment and of course the customers rejected this. Prospects would take the “sensor”, and Bluetooth tag into the yard, and see if it appears on the map. It didn’t because the main algorithm took like 30 minutes to figure out locations of these units. &lt;a href=&quot;#fn20&quot; class=&quot;footnote-ref&quot; id=&quot;fnref20&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;20&lt;/sup&gt;&lt;/a&gt; Now our main customer was happy with that, because they were already bought in. However, if you want to sell this locating system, this is the first bullshit check you do. I think one of the OKRs&lt;a href=&quot;#fn21&quot; class=&quot;footnote-ref&quot; id=&quot;fnref21&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;21&lt;/sup&gt;&lt;/a&gt; at this time was to set up the project without any assistance from the internal team. In essence, to make it a do it yourself experience for the customer. This as a goal was batshit insane. Not only were the deals too large for this to be done. The tech was far from being polished enough to be used like this. Furthermore these would be recurring deals. so cheaping out on some manpower for a one-time setup cost is kinda crazy. I brought this to the attention of the product manager, and he agreed. &lt;a href=&quot;#fn22&quot; class=&quot;footnote-ref&quot; id=&quot;fnref22&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;22&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Because we were sort of “free” to decide what to work on, I strongly argued in favor of making sales easier. Another topic was for example to add admin pages, we were currently just modifying stuff directly into the database. We decided to go all in on just modifying the technology so that we could pass technical trials and sell to customers. Whatever it took. There were two major issues:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;Customers had a poor or no mental model of how the (hardware) technology worked. In that they didn’t understand Bluetooth&lt;a href=&quot;#fn23&quot; class=&quot;footnote-ref&quot; id=&quot;fnref23&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;23&lt;/sup&gt;&lt;/a&gt; signals.&lt;/li&gt;
&lt;li&gt;We’d also address taking a sensor and tag to the yard and not get a ping on the map. The system had to become “live”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We “tackled” these problems with something called “trial” mode. The designer made a ton of screens explaining all this stuff and have an automated way of guiding a new user through all of it.&lt;a href=&quot;#fn24&quot; class=&quot;footnote-ref&quot; id=&quot;fnref24&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;24&lt;/sup&gt;&lt;/a&gt; &lt;a href=&quot;#fn25&quot; class=&quot;footnote-ref&quot; id=&quot;fnref25&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;25&lt;/sup&gt;&lt;/a&gt; One nice thing is that I could let the other engineer implement most of the frontend and backend features for supporting that, while I focused on actually making the signals available at all. Keep in mind we did not just have a “there is a database” backend called the server, we also had the “figure out what a signal is” backend called reality capture. I worked on that reality capture part. This gave the other engineer the opportunity to grow more, and come up with her own designs which we could work with.&lt;a href=&quot;#fn26&quot; class=&quot;footnote-ref&quot; id=&quot;fnref26&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;26&lt;/sup&gt;&lt;/a&gt; We finished most of this around May.&lt;/p&gt;
&lt;p&gt;I think around May in 2024 the money had run out for this project. So the other engineer got pulled, which was annoying because she just had gotten reasonably productive to do small full-stack features on her own. Another quarter or two and she’d be amazing. The designers’ contract just wasn’t renewed at all. &lt;a href=&quot;#fn27&quot; class=&quot;footnote-ref&quot; id=&quot;fnref27&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;27&lt;/sup&gt;&lt;/a&gt; Despite the cash burn being lowered, this project was far from saved, we were still scraping by. And the threats from upper management continued, and sales kept on fumbling.&lt;a href=&quot;#fn28&quot; class=&quot;footnote-ref&quot; id=&quot;fnref28&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;28&lt;/sup&gt;&lt;/a&gt; We knew the particle hardware we were using wasn’t performing well. But obviously we’d get no hardware resources. It was just me and the algorithms engineer left doing technical work. And the product manager to deal with customers and sales.&lt;/p&gt;
&lt;style&gt;
img[src=&quot;images/2025/particle.webp&quot;]{
  width:unset;
  height: 20em;
}
&lt;/style&gt;
&lt;figure id=&quot;particle&quot;&gt;
&lt;img src=&quot;images/2025/particle.webp&quot; alt=&quot;Particle sensor and bleutooth tag beacons&quot; /&gt;
&lt;figcaption&gt;
Particle sensor and bleutooth tag beacons
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;One prospect customer who we were talking to for years at this point was located in Denmark. We knew the hardware wasn’t performing well because of trying to get the system to work with them. They told us, “show it works and we’ll use it”. It didn’t work. For example they had sensors in their little trucks driving by these walls with Bluetooth tags on them. The sensors would pick up no signals at all. I think the product manager had visited this place five times already by that point. Everytime the algorithm engineer and the PM would have a new tactic to “crack” this yard. He went again around May, and failed. But as we know now there were serious &lt;a href=&quot;%7Bfilename%7D/firmware-sins.md&quot;&gt;fundamental issues&lt;/a&gt; with the firmware. So I don’t think &lt;a href=&quot;https://en.wikipedia.org/wiki/Trilateration&quot;&gt;trilateration&lt;/a&gt;&lt;a href=&quot;#fn29&quot; class=&quot;footnote-ref&quot; id=&quot;fnref29&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;29&lt;/sup&gt;&lt;/a&gt; could’ve worked in any case without firmware upgrades.&lt;/p&gt;
&lt;p&gt;The sensors worked well enough to give you a live proximity-based location. This would just attach the sensor GPS location to a Bluetooth tag on extremely close proximity, say smaller than a meter. We could just measure the signal strength required for that, it is reliable. The backend was just a loop essentially, constantly querying the &lt;a href=&quot;https://aws.amazon.com/timestream/&quot;&gt;timestream&lt;/a&gt;&lt;a href=&quot;#fn30&quot; class=&quot;footnote-ref&quot; id=&quot;fnref30&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;30&lt;/sup&gt;&lt;/a&gt; database for updates at small incrementing windows. It’d be attaching the signals to gateway locations if the signal strength was high enough and the time stamps were close enough. This one feature, we tested the shit out of, it was our ace in the hole.&lt;/p&gt;
&lt;p&gt;Something else happened around May, the head of software decided that this project could benefit from an app. And he decided to make a prototype. The QR code scanning in app was much better than whatever we could provide on the web. And the app had Bluetooth capabilities, which browsers to this day &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Bluetooth_API&quot;&gt;can’t access&lt;/a&gt;. So I saw some good growth potential in this and was so relieved he took the initiative. Now &lt;a href=&quot;https://flutter.dev/&quot;&gt;Flutter&lt;/a&gt; is far from perfect, and &lt;a href=&quot;https://dart.dev/&quot;&gt;Dart&lt;/a&gt; isn’t a great language to work in.&lt;a href=&quot;#fn31&quot; class=&quot;footnote-ref&quot; id=&quot;fnref31&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;31&lt;/sup&gt;&lt;/a&gt; But there was no way I could also maintain an app on my own aside from dealing with the glaring problems this system had. So I’d not look a gift horse in the mouth and thanked the head of software for his contributions.&lt;/p&gt;
&lt;p&gt;We had scheduled the check in Denmark beginning of July. The person managing our meeting, let’s call him Bob, was actually quite happy to arrange some Danish delights. The product manager told him to arrange whatever for lunch, but I asked for some local Danish specialties. He seemed to be quite happy to do that. Bob was quite a character actually. He was completely disinterested in this project, he just wanted to get this done. His organization upper management apparently told him to do these checks, and he was going to, with minimal of efforts. But Bob seemed to be delighted to share about Danish culture and cuisine, what a joyful reminiscence. The check involved production people attaching a bunch of beacons to various units. We’d then use the system to find them. Of course the system failed. But not just because of the bad firmware. Also because the way this factory was managed was extremely strange and inefficient. They’d move their trailers over to one part of the yard. Perform QA. Send them to another part of the yard to reshuffle.&lt;a href=&quot;#fn32&quot; class=&quot;footnote-ref&quot; id=&quot;fnref32&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;32&lt;/sup&gt;&lt;/a&gt; Then send them to whatever storage, then go back for reshuffling, etc. There was no rhyme or reason to any of this. Mind you these are walls they were carrying. These are heavy loads, and they used heavy machinery, but nobody had any clue how they were using these tools. We did not know this either, but we had scheduled several days to prepare for this check, and at some point I started asking the PM about what was going on, which made him think about it.&lt;a href=&quot;#fn33&quot; class=&quot;footnote-ref&quot; id=&quot;fnref33&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;33&lt;/sup&gt;&lt;/a&gt; At several times the system would locate these units in the middle of the road. They probably were in the middle of the road for a while, but we had no sensors in those reshuffle or QA areas, so our system wouldn’t further update even if they got moved there. We had an in real life phantom read. Honestly, we were set up to fail from the start. But no one knew how unfair this tech check was, even at the factory.&lt;/p&gt;
&lt;p&gt;Here I had a little epiphany, all that talk about CO₂ reduction for the other projects, may be in fact also be true for this project. Upper management, the same one threatening to cancel us all the time, deeply cared about carbon reduction. Nobody realized this because nobody has spend hours upon hours in the yard trying to get a tracking solution to work. Nobody has ever put any extra thoughts around the yard. So in fact a project I initially joined for the challange and for using Haskell, I stuck around because I liked the people, may in fact also be helping the environment? &lt;a href=&quot;#fn34&quot; class=&quot;footnote-ref&quot; id=&quot;fnref34&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;34&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now the fact the system failed was a huge issue for us. We had some time however, we had planned the entire week for doing this check. If we’d failed this check it would be a huge blow against us. In fact on the road to this check the PM was already casually asking me if I thought he’d be a good PM for other software companies. I listened to what was not being said. I think he’s awesome, but we were fucking cooked. However, we had our ace up our sleeve. the proximity algorithm.&lt;/p&gt;
&lt;p&gt;On judgment day, before the check was being done by Bob, the PM told me to grab a sensor and go walk by all units, he’d do the same but from the other side of the yard. the yard being 300x250m, which is around eight football fields. It started raining heavily. Find a tag, press the sensor to it, wait a second, then move on.&lt;a href=&quot;#fn35&quot; class=&quot;footnote-ref&quot; id=&quot;fnref35&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;35&lt;/sup&gt;&lt;/a&gt; Rinse and repeat while getting soaked. Before the check I went back into the office making sure everything was updated. Unfortunately some units had updated to the wrong location due to the other trilateration algorithm sending updates that override proximity. Here the algorithm engineer, the PM and I had a healthy debate. The algorithm engineer wanted a fair check, The PM and I knew there was nothing fair here. The PM and I wanted to force update the wrongly located units in the database. We ended up doing that by matter of vote&lt;a href=&quot;#fn36&quot; class=&quot;footnote-ref&quot; id=&quot;fnref36&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;36&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Bob had already arrived, but the PM asked for a moment. The PM told me to also put one of these sensors in my bag, we’d just walk with them on our person while doing the check. I was shivering from being soaked. I guess Bob didn’t put two and two together as he didn’t care.&lt;a href=&quot;#fn37&quot; class=&quot;footnote-ref&quot; id=&quot;fnref37&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;37&lt;/sup&gt;&lt;/a&gt; With the first unit Bob tried to let us fail on a technicality. But the PM went hard against that. The sun had come in, and these checks became a pleasant walk. Bob started cracking jokes and smoking cigarettes. The next ones were all passing (of course), in fact when the customer would check he would at times see the system update in front of his eyes. And just accept it as normal. Not knowing we’d have sensors on our person. &lt;a href=&quot;#fn38&quot; class=&quot;footnote-ref&quot; id=&quot;fnref38&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;38&lt;/sup&gt;&lt;/a&gt; Bob believed it worked. some rough spots were blamed on the newly developed app, but overall he was happy. We passed the check by the skin of our teeth.&lt;/p&gt;
&lt;style&gt;
img[src=&quot;images/2025/danish-rye-bread.jpeg&quot;]{
  width:unset;
  height: 20em;
}
&lt;/style&gt;
&lt;figure id=&quot;particle&quot;&gt;
&lt;img src=&quot;images/2025/danish-rye-bread.jpeg&quot; alt=&quot;Danish rye bread&quot; /&gt;
&lt;figcaption&gt;
Danish rye bread, a local delicacy.
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This was huge. We’ve been scraping by and losing members for the past half year. But we managed to sell. No longer could upper management blame the technical working of our system for sales failures. Annoyingly this particular deal fell through anyway, but not because of the technical capabilities of the system. I think this did buy us a chunk of time however to actually address the underlying issues. During this check we had spotted many other issues with the system. Fun things such as DDoSing ourselves by having a bag of tags next to the sensor (which caused a bit of panic the day before judgment). I addressed all these issues.&lt;/p&gt;
&lt;h1 id=&quot;winning&quot;&gt;Winning&lt;/h1&gt;
&lt;p&gt;We also started doing another trial for a potential new large customer, similar to the one in denmark. This time it would not take seven trips from the PM. We had proximity algorithm to convince them that we could find locations of units. Actually one of the sensors failed during this check, fortunately they had a backup, but aside that we past this tech trial on first go. We confirmed here that if you convince people it works swiftly, they’ll be a lot less thorough in their technical checks. This trial in September 2024, I believe was still on the old crummy firmware. We passed so “easily” because we failed so hard and often in Denmark and learned. Furthermore the algorithm engineer did her magic, and had convinced them the system could be used for &lt;a href=&quot;https://nl.wikipedia.org/wiki/Lean_manufacturing&quot;&gt;LEAN manufacturing&lt;/a&gt;. Unfortunately the customer had arranged no experts for that check there at the time. So they didn’t realize what they were sitting on. But they were convinced the system worked and was something that they wanted. This came back to us in January with some good news once they finally found a guy to judge that, and he was enthusiastic.&lt;/p&gt;
&lt;p&gt;Then the next major issue started popping up for our existing customer. The Bluetooth tag batteries around July started dying. We thought we solved this by just sending new beacons. The new ones had better settings which were supposed to make them last for 4 years. Our existing customer also found the algorithm wouldn’t work on another part of the yard, we worked around this by doing those manual forced updates with proximity. Actually they were happy to take sensors into the yard. Around September I started working on the firmware, described &lt;a href=&quot;%7Bfilename%7D/firmware-sins.md&quot;&gt;elsewhere&lt;/a&gt; so I won’t go into it. This made proximity significantly better, and temporarily killed the other algorithms, due to an excess of data causing it to run out of memory.&lt;/p&gt;
&lt;p&gt;Around October we won an award for smart data collection in construction, we were nominated by our one and only customer. Furthermore around Christmas we got good feedback from them. They had managed to lose around 30 units in SAP and managed to find them all with our system! I knew at the time it was just my proximity algorithm that was operational. Because the new firmware had killed the trilateration algorithm. So I was a little confused by this. Furthermore our own audits showed that we could seriously work on accuracy. I think what happened was that one of their employees consistently took a sensor into the yard. I’m not really sure, but if they’re happy, I’m happy.&lt;/p&gt;
&lt;p&gt;Even after winning the award and having this major customer in the pipeline, we still got more threats of upper management. We also got more curve balls thrown at us. For example the temperature product required my services for 2 weeks. I was the only software engineer trying to make this logistic stuff work, they had seven people working on their temperature tech, and they couldn’t do this one algorithm integration in time. I was supposed to help them for 2 weeks. I finished the task in 2 days. After which they started inventing other tasks, I said “no thanks”. Other people from upper management who had been ignoring this project for years at this point all of a sudden wanted to get involved. I think people were noticing this project was starting to win. In their helpfulness they blocked architecture changes until detailed documentation was made for example. I’ve no idea how to deal with these requests. Spending two days on documenting while one of the main algorithms is down seems irresponsible. I just stopped doing architecture changes, they were mostly cost saving anyway, and optional for now.&lt;/p&gt;
&lt;p&gt;The PM would become father, and he’d go on a three-month break from the job in December. We knew this was coming up so we were preparing for that point. The algorithm engineer and I would share responsibilities. I was anxious for this period. One of our main concerns was to keep the commercial team focused. Doing a weekly meeting turned out to be highly successful, actually the main sales guy liked doing them and requested to continue doing them after the PM got back. We made this work. Come on, compared to what we’ve been through in Denmark, this was easy right? It was.&lt;/p&gt;
&lt;p&gt;For most of December I worked on signal processing. This was some new feature where we sent signals directly to the backend so we could support this “detected here” status. This was one of the main features the new customer would use, to determine on which site a unit is. It’s a more general way of locating units, rather than by coordinates you just give it a site name. This is easy because you know on which site a sensor is, so all you have to do is pick up a signal and associate it to a sensor. Before we fetched the signals from timestream but that was kind of expensive. This approach used a simple queue.&lt;/p&gt;
&lt;p&gt;There is plenty of other high impact stuff to do. Fore example the beacon battery issue exploded, we did some analyses on an existing batch and found that around 5% of the new batteries were unacceptably low. I already had written an app to check for beacon settings and battery settings, it was just a bit slow. However I modified it so that it would highlight bad settings in red. This made sifting through all these beacons (thousands of them) a lot faster. It’s available &lt;a href=&quot;https://github.com/jappeace/kbeacon-ota-tool&quot;&gt;opensource&lt;/a&gt;. With the things learned from that development I also built a liveliness check in the registration app.&lt;a href=&quot;#fn39&quot; class=&quot;footnote-ref&quot; id=&quot;fnref39&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;39&lt;/sup&gt;&lt;/a&gt; This should prevent the system from accepting any dead or low battery Bluetooth tags.&lt;/p&gt;
&lt;figure&gt;
&lt;iframe src=&quot;https://www.youtube.com/embed/rGtHcDdJSRY&quot; title=&quot;Ota app demo&quot; frameborder=&quot;0&quot; style=&quot;height: 30em; float: right;&quot; allow=&quot;accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&gt;
&lt;/iframe&gt;
&lt;figcaption&gt;
Over the air settings check app demo
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We’re in March now. That big customer signed the deal, and we likely got another construction site. Currently we’re servicing two locations; soon this will grow to fourteen. We’re winning and we likely won’t be able to keep up with the work. Which is a much better problem to have than being threatened by cancellation. Whilst that’s going on we’re still surprised by leadership with cryptic and somewhat intimidating remarks—for example, asking “is this really aligned with our vision?”. Their vision being to tackle carbon impact in construction. Which is ironic, considering the experience in Denmark.&lt;a href=&quot;Specically%20the%20fact%20they%20drag%20these%20walls%20around%20the%20yard%20all%20the%20time.&quot;&gt;^danish-madness&lt;/a&gt; I suppose they’d just not believe us. Despite the irony and the fact we just had this huge deal done, we’re still having these kinds of questions being raised. I think I requested a warm body to deal with those battery replacements. This request got denied. It’s an odd situation to be in, where you sort of know already you’re going to be short on manpower, but upper management still believes you’re a bad project. We triumphed in Denmark, you think a salty manager is going to stop us?&lt;/p&gt;
&lt;p&gt;As long as we focus on the right stuff to build we’ll be fine. We’ve been focusing on stuff that has impact, and I think about 90% of the things we worked on had impact. We bought time by dealing with our customers request and get a renewal, that time we used to make the product sell able via proximity, which bought us more time to fix the fundamental firmware problems. Which made the product actually good. There are other large problems we have in this project. For example the particle data operations are hugely expensive, but this company can build its own hardware. Upper management just likes to kill our requests. Ironically enough, it’s costing &lt;em&gt;them&lt;/em&gt; money, not me. It causes me more work because I work around it these problems with more firmware modifications, for example, I introduced a sleep mode where we disable the sensors during off hours. I’ve never claimed to be good at firmware, but even a slowly produced implementation of these changes causes a huge impact. Despite how cooked internal politics is for this company, with two major customers now, many sites and getting the award, we can say we’re winning this unfair game.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;So this also involves getting familiar with whatever style the organization is using. Usually various companies have various styles.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;How do you lose a wall? Imagine a concrete precast factory that constantly is churning out walls and other precast elements. These walls are stored in a yard several football fields wide, filled with gray concrete. Normally they record where they’re stored in &lt;a href=&quot;https://www.sap.com/&quot;&gt;SAP&lt;/a&gt; an inventory tracking tool. If they need the wall below another one, they may move it somewhere else and SAP gets stale. In practice these walls may be moved a lot and get lost. These walls often wait for months to be shipped to a construction site.&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;Eg a precast wall. Several of which stacked upon eachother is called a stack.&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;You’d say having monitoring is rather important, but startups often forget these “basics” of software engineering.&lt;a href=&quot;#fnref4&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn5&quot;&gt;&lt;p&gt;Katip is great and structured logging is really nice, that service logz is fragile however, it denies the existence of heterogeneous lists in Java which Haskell tuples get encoded to as JSON.&lt;a href=&quot;#fnref5&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn6&quot;&gt;&lt;p&gt;There still to this day is an entire &lt;a href=&quot;%7Bfilename%7D/mtl.md&quot;&gt;MTL&lt;/a&gt; based framework to stub out logic and run tests in memory. ONE of my first suggestions was to delete that and instead just use higher order functions to stub things out, but some high up chiefs decided against that because they liked seeing the possible effects in the type signature. Because most logic resided in the database I think at this point I’ve deleted most tests that use this. These in memory tests didn’t ever catch any bugs and were just a maintenance burden. Instead we now do full integration tests that hit the database. The concern down the line is that our test suite becomes slow, but that’s a problem for future me. One of my main productivity increase was to not be afraid of introducing tech debts like these. Because if the project dies right now because you don’t get anything done having perfect code just doesn’t matter. And I’ve kicked that “slow tests” can extremely far down the road at previous jobs. At supercede we had thousands of database hitting tests still run under 10 minutes.&lt;a href=&quot;#fnref6&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn7&quot;&gt;&lt;p&gt;Normally it’s the software engineers asking for haskell and managers resisting the encroachment.&lt;a href=&quot;#fnref7&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn8&quot;&gt;&lt;p&gt;Haskell language server. an LSP implementation for haskell. this provides IDE like experience for editors. It’ll make your text editor give hints.&lt;a href=&quot;#fnref8&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn9&quot;&gt;&lt;p&gt;Asside from the time pressure for producing features and having to learn haskell, having this program randomly crash on you as your only source of feedback is infuriating.&lt;a href=&quot;#fnref9&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn10&quot;&gt;&lt;p&gt;If they were to not obsess over architecture all the time this wouldn’t have been such a big problem. By the time I joined this guy already knew how to navigate syntax and how to fix bugs rapidly. The mental overhead was of his own creation.&lt;a href=&quot;#fnref10&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn11&quot;&gt;&lt;p&gt;I call it ideology because I think programming languages are more like a culture you buy into rather than a mere technological choice. Every general purpose programming language is Turing complete and therefore equivalent in capability. So logically what remains is cultural preference. In this view choosing one is more like choosing a “workstyle”, a “way of thinking” or set of ideas to buy into. As opposed the more traditional view which says. It makes more sense to ask “what system of values Haskell promotes versus JavaScript?”, rather than to ask “what can I do with Haskell verses JavaScript?”. The latter question is meaningless. Having said that I do think you can be a lot more productive in Haskell than JavasScript because the libraries are better designed, with fewer surprises and the type system will catch so many small issues in a thorough manner. It’s better then other commercially available typed languages because it reduces to a single expression. This difference can be reduced to a value question as well: Do you care about individual developer productivity, or do you care about having a sufficiently large manpower pool? There are more JavaScript developers than Haskell developers.&lt;a href=&quot;#fnref11&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn12&quot;&gt;&lt;p&gt;Later I found out that he made a bunch of suspicious technical choices, but I think most of these decisions came from being angry instead of lack of skill&lt;a href=&quot;#fnref12&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn13&quot;&gt;&lt;p&gt;I myself never bothered learning Linear Haskell for example, or can’t be bothered with the evaluation order of type families, it’s just not interesting. I don’t think you gain a lot by learning that stuff. You could do something fun instead y’know, write a giant blog post on your job for example..&lt;a href=&quot;#fnref13&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn14&quot;&gt;&lt;p&gt;I think I succeeded with this. People no longer shy from just jumping out of their comfort zone and helping eachother out.&lt;a href=&quot;#fnref14&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn15&quot;&gt;&lt;p&gt;The product manager made it clear we had to get stuff done fast.&lt;a href=&quot;#fnref15&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn16&quot;&gt;&lt;p&gt;I’ve only seen the customer onboarding document, and it was incomplete.&lt;a href=&quot;#fnref16&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn17&quot;&gt;&lt;p&gt;The foundational issue being the firmware.&lt;a href=&quot;#fnref17&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn18&quot;&gt;&lt;p&gt;Finally the designer got to do something. This wasn’t his fault.&lt;a href=&quot;#fnref18&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn19&quot;&gt;&lt;p&gt;I did nothing “genius” of course, I just made a boring, traditional design out of it. The reason it was so flawed is because the previous tech lead was afraid of Haskell.&lt;a href=&quot;#fnref19&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn20&quot;&gt;&lt;p&gt;Rather than streaming the signals and doing trilateration on the fly, these were processed as a batch. I don’t think anyone at the time had expected live updates to be a requirement. It is if you want to sell this. There is no reason why it shouldn’t be able to do this on the fly, but the system was simply not implemented like that. This algorithm was fully written in Python.&lt;a href=&quot;#fnref20&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn21&quot;&gt;&lt;p&gt;Objective and key result.&lt;a href=&quot;#fnref21&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn22&quot;&gt;&lt;p&gt;This is one of the reasons I stuck around. The fact they listen to uncomfortable things like this is one of the big reasons I decided to stay longer at this project. I’m not a business guy or strategist, just a developer. But if you come with logically founded arguments they listen.&lt;a href=&quot;#fnref22&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn23&quot;&gt;&lt;p&gt;Bluetooth just works over radio, all Bluetooth does is specify a protocol.&lt;a href=&quot;#fnref23&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn24&quot;&gt;&lt;p&gt;Finally the designer got to do something. This wasn’t his fault.&lt;a href=&quot;#fnref24&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn25&quot;&gt;&lt;p&gt;Looking back, I think the product manager still had a small hope for creating a do it yourself experience. Which is fair because going to these factories and construction sites is a big undertaking. We later found out these screens wouldn’t work, but the back-end stuff to support it, and having live updates were fantastic!&lt;a href=&quot;#fnref25&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn26&quot;&gt;&lt;p&gt;I think the important part here was that she could make mistakes and learn from them. I was always available to bail her out if necessary. Most of her issues were small details, such as having functions with the same name causing confusion.&lt;a href=&quot;#fnref26&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn27&quot;&gt;&lt;p&gt;He ended up being a giant distraction because he kept organizing meetings to discuss stuff which we just couldn’t implement.&lt;a href=&quot;#fnref27&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn28&quot;&gt;&lt;p&gt;Aside story: Around this time the one irish precast factory let out a competition for a technical solution for precast factories that basically described our system. There was some subsidy by the Irish government. We were by far the best suited to win that and somehow lost. I don’t know what happened, but people say there is a lot of corruption in construction, another fun thing 🙂&lt;a href=&quot;#fnref28&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn29&quot;&gt;&lt;p&gt;Trilateration involves locating by making triangles out of observations.&lt;a href=&quot;#fnref29&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn30&quot;&gt;&lt;p&gt;I would’ve used influxdb, but one of the engineers who wrote reality capture went gungho on Amazon services.&lt;a href=&quot;#fnref30&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn31&quot;&gt;&lt;p&gt;My biggest issue is the lack of sum types which make error handling hard. You get enums but no heterogeneous struct per tag. It also inherits all the equality issues that Java has, making working with collections challenging.&lt;a href=&quot;#fnref31&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn32&quot;&gt;&lt;p&gt;Reshuffling means, moving a concrete wall from one trailer to another to be patched up. This happens with large diesel powered cranes.&lt;a href=&quot;#fnref32&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn33&quot;&gt;&lt;p&gt;I think the PM just asked one of the guys in the yard. But these people don’t talk much to the office staff. Obviously people working in the yard know what’s going on. However their managers’ managers don’t know. Which are the office staff and we were judged by office staff.&lt;a href=&quot;#fnref33&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn34&quot;&gt;&lt;p&gt;Now, I have no aspirations to actually help the environment, because I feel this is mostly an energy issue. But I am definitely concerned about it. So I count this as a bonus.&lt;a href=&quot;#fnref34&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn35&quot;&gt;&lt;p&gt;We noticed at the time the procedure didn’t always work. I now know that this process probably only worked half the time because the sensor would spend 20 seconds of the minute sending gps signals and not doing any Bluetooth. These are all firmware issues I fixed &lt;em&gt;after&lt;/em&gt; denmark…&lt;a href=&quot;#fnref35&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn36&quot;&gt;&lt;p&gt;Normally the three of us argue till we reach consensus, this is an advantage of a small team. But there was no time to do this this time, the check was coming.&lt;a href=&quot;#fnref36&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn37&quot;&gt;&lt;p&gt;I was soaked because I just had spend 2 hours in the rain force updating the system.&lt;a href=&quot;#fnref37&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn38&quot;&gt;&lt;p&gt;This is dishonest I suppose. We just needed time to figure out for example the firmware. We needed internal confidence, to get firmware engineers. We were setup to fail on this site. How do you judge us?&lt;a href=&quot;#fnref38&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn39&quot;&gt;&lt;p&gt;The registration app is different from the setting check app. The setting check app isn’t customer facing.&lt;a href=&quot;#fnref39&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Firmware lemons 🍋</title>
    <link href="https://jappieklooster.nl/firmware-lemons.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2024-11-02:/firmware-lemons.html</id>
    <published>2024-11-02T00:00:00Z</published>
    <updated>2024-11-02T00:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;style&gt;
img[src=&quot;images/2024/calc-gamble.png&quot;]{
  height: 20em;
  float: right;
  margin: 2em;
  width:unset;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;img src=&quot;images/2024/calc-gamble.png&quot; alt=&quot;Life and lemons&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Life and lemons&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Ever found yourself fixing a problem you weren’t hired to solve? To the point where you’re under qualified? That’s what happened when I dove into firmware. It was my suggestion, nobody &lt;em&gt;asked&lt;/em&gt; me to do this, but we&lt;/p&gt;</summary>
    <content type="html">&lt;style&gt;
img[src=&quot;images/2024/calc-gamble.png&quot;]{
  height: 20em;
  float: right;
  margin: 2em;
  width:unset;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;img src=&quot;images/2024/calc-gamble.png&quot; alt=&quot;Life and lemons&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Life and lemons&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Ever found yourself fixing a problem you weren’t hired to solve? To the point where you’re under qualified? That’s what happened when I dove into firmware. It was my suggestion, nobody &lt;em&gt;asked&lt;/em&gt; me to do this, but we needed better scanners, better hardware even, and we couldn’t get it due to politics. They asked us to get more customers, before we could get better hardware. Cost was the main issue, this project was perceived as too expensive. But the irony was that we needed better hardware to get more customers. We had to break this deadlock.&lt;/p&gt;
&lt;p&gt;I had never even seen any firmware before! But it was pretty clear at this point our Bluetooth scanners were underperforming. They are the source of all data, and they’d catch out about 5 signals per second. Which is far lower than what you can see on any Bluetooth capable device. I worked at this place for about a year, before this even came up. We tried doing fancy startup things, and underachieved. For example we wanted to detect if a “lift” was happening, but only got a single observation from the scanner for a two minute period.&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; About two months ago I brought that the scanner firmware maybe bad. We thought the scanners worked at peak performance before that. Kind of silly looking back. We naively assumed we were set up for success, but we were given lemons.&lt;/p&gt;
&lt;h2 id=&quot;experiment&quot;&gt;Experiment&lt;/h2&gt;
&lt;p&gt;My colleague tracked down the packet size configuration and increased it as an experiment. This doubled the performance of the device. I was relieved by this; I sensed the deadlock breaking and could smell lemonade. If your goal is to figure out what’s going in reality with Bluetooth scanners, and you double the performance with a small firmware modification. You know you’re doing something right.&lt;/p&gt;
&lt;p&gt;I took over from my colleague, because I was there to write code. Initially I was so bad at this that she had to bail me out a couple of times. With tasks such as flashing builds or dealing with bricked hardware. The first week I essentially “did” nothing, because I was just struggling with getting builds out or busy reading the &lt;a href=&quot;https://docs.particle.io/getting-started/device-os/introduction-to-device-os/&quot;&gt;docs&lt;/a&gt; and understanding what was going on. If a device bricks due to faulty firmware (think segfaults), it frustratingly only shows a red blinking light. No &lt;a href=&quot;https://sourceware.org/gdb/&quot;&gt;GDB&lt;/a&gt; for you. You can no longer put new firmware on it either, but there is a reset trick&lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; for that. My colleague recommended that I make a small, baby-step changes. Test each small change out out on the device making sure it doesn’t crash. &lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;sorting&quot;&gt;Sorting&lt;/h2&gt;
&lt;p&gt;Anyway, I got better. In the second week I got a build that sorted on signal strength values. &lt;a href=&quot;#fn4&quot; class=&quot;footnote-ref&quot; id=&quot;fnref4&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; We believed the machine was sending random updates, whereas we were mostly interested in strong signals. &lt;a href=&quot;#fn5&quot; class=&quot;footnote-ref&quot; id=&quot;fnref5&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt; So by sorting we’d just get the best information out of the machine, neglecting weak signals. This again showed an improvement, not as good as the increased packet size, but a good step forward.&lt;/p&gt;
&lt;h2 id=&quot;mutex-nonsense&quot;&gt;Mutex nonsense&lt;/h2&gt;
&lt;p&gt;The following week I tackled the concurrency issue. I knew this was an issue because there was a &lt;a href=&quot;https://stackoverflow.com/questions/34524/what-is-a-mutex&quot;&gt;mutex&lt;/a&gt; that excluded the Bluetooth scanner from running while sending of packets was happening via the SIM card (and vice versa). They put instructions on a thread, but nothing ran concurrently. For example here is the scan thread doing the Bluetooth scanning:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode cpp&quot;&gt;&lt;code class=&quot;sourceCode cpp&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;void&lt;/span&gt; Beaconscanner&lt;span class=&quot;op&quot;&gt;::&lt;/span&gt;scan_thread&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;param&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;(!&lt;/span&gt;_instance&lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt;_run&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            os_thread_yield&lt;span class=&quot;op&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;#cb1-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;cf&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;#cb1-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;#cb1-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        custom_scan_params&lt;span class=&quot;op&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;#cb1-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;_instance&lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt;_scan_done&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;// mutex here disables the thread on true&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;#cb1-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            os_thread_yield&lt;span class=&quot;op&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-10&quot;&gt;&lt;a href=&quot;#cb1-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;cf&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-11&quot;&gt;&lt;a href=&quot;#cb1-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-12&quot;&gt;&lt;a href=&quot;#cb1-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; elapsed &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; millis&lt;span class=&quot;op&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-13&quot;&gt;&lt;a href=&quot;#cb1-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;_instance&lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt;_run &lt;span class=&quot;op&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; millis&lt;span class=&quot;op&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;-&lt;/span&gt; elapsed &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt; _instance&lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt;_scan_period&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-14&quot;&gt;&lt;a href=&quot;#cb1-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            Vector&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;BleScanResult&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; cur_responses &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; BLE&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;scan&lt;span class=&quot;op&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-15&quot;&gt;&lt;a href=&quot;#cb1-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            _instance&lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt;processScan&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;cur_responses&lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-16&quot;&gt;&lt;a href=&quot;#cb1-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-17&quot;&gt;&lt;a href=&quot;#cb1-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        _instance&lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt;_scan_done &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-18&quot;&gt;&lt;a href=&quot;#cb1-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        os_thread_yield&lt;span class=&quot;op&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-19&quot;&gt;&lt;a href=&quot;#cb1-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-20&quot;&gt;&lt;a href=&quot;#cb1-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and then we got the main loop consuming it:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode cpp&quot;&gt;&lt;code class=&quot;sourceCode cpp&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;void&lt;/span&gt; Beaconscanner&lt;span class=&quot;op&quot;&gt;::&lt;/span&gt;loop&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;bool&lt;/span&gt; publishScans&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;#cb2-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;_scan_done&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;// mutex here, only publish on true&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;#cb2-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        publish_all&lt;span class=&quot;op&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;#cb2-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        _scan_done &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;#cb2-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;#cb2-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You may wonder how these threads even communicate, no handles are passed around. The answer is of course global variables and the use of various locking macros.&lt;a href=&quot;#fn6&quot; class=&quot;footnote-ref&quot; id=&quot;fnref6&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;6&lt;/sup&gt;&lt;/a&gt; Not that the locking matters because &lt;code&gt;_scan_done&lt;/code&gt; is used as a mutex. So we’ve two threads running, but the relevant code never actually runs at the same time.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;They wrote code, and then wrote other code to undo their initial code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They took the effort of putting the Bluetooth scanner on a thread. And then wrote a mutex to undo the threading. It would’ve been more efficient if all was done on the main loop with no threading at all! Once I realized this was happening I was baffled. The author got paid good money to undo his own code with more code, resulting in firmware like a sour lemon.&lt;/p&gt;
&lt;p&gt;I tried explaining this to my dear colleagues, I said something like “we’ve threads but no concurrency”. Perhaps this was too dense, but to be fair it’s hard to explain nonsense. Fortunately this weirdness was also visible in the observations. At times we were just getting no observations when we’d expect some. By the time we were talking about these observations, I already had a build, because I knew the code was nonsense and had addressed it.&lt;a href=&quot;#fn7&quot; class=&quot;footnote-ref&quot; id=&quot;fnref7&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;7&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;fixing-concurrency&quot;&gt;Fixing concurrency&lt;/h2&gt;
&lt;p&gt;The fix involved deleting it all. Both the locks and the mutex. Instead I used a queue for inter thread communication. Queues is doing threads on easy mode, and I had no-one to impress, so I did easy mode. However, even in easy mode this was still quite challenging to do. Partly due to my inexperience with C-like programming. The queue I ended up using looked like &lt;a href=&quot;https://docs.particle.io/firmware/software-design/threading-explainer/?q=thread#os_queue_create&quot;&gt;this&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode c&quot;&gt;&lt;code class=&quot;sourceCode c&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; os_queue_create&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;os_queue_t&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; queue&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;size_t&lt;/span&gt; item_size&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;size_t&lt;/span&gt; item_count&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; reserved&lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It’s a bit wack; you reserve some memory for the queue, giving you a &lt;code&gt;os_queue_t*&lt;/code&gt;. Then you’ve to initialize that memory with &lt;code&gt;os_queue_create&lt;/code&gt;. This fills in some fields of the structure. I got stuck on using &lt;code&gt;os_queue_put&lt;/code&gt; and &lt;code&gt;os_queue_take&lt;/code&gt; for a while, which caused me red blinking light grief&lt;a href=&quot;#fn8&quot; class=&quot;footnote-ref&quot; id=&quot;fnref8&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;8&lt;/sup&gt;&lt;/a&gt; (segfaults):&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode c&quot;&gt;&lt;code class=&quot;sourceCode c&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;#cb4-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; os_queue_put&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;os_queue_t queue&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; item&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; system_tick_t delay&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; reserved&lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;#cb4-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; os_queue_take&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;os_queue_t queue&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; item&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; system_tick_t delay&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; reserved&lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I think the issue was that I tried putting in a &lt;a href=&quot;https://docs.particle.io/reference/device-os/api/bluetooth-le-ble/blepeerdevice/#blescanresult&quot;&gt;&lt;code&gt;BleScanResult&lt;/code&gt;&lt;/a&gt; directly. But it contains some pointers, and this queue wants you to copy over all data as a continuous memory block. &lt;code&gt;void*&lt;/code&gt; in this case means give me whatever memory pointer, &lt;a href=&quot;#fn9&quot; class=&quot;footnote-ref&quot; id=&quot;fnref9&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;9&lt;/sup&gt;&lt;/a&gt; and the &lt;code&gt;os_queue_create&lt;/code&gt; function already told how large it should be. So instead of putting everything on the queue, I just made a struct with all relevant information:&lt;/p&gt;
&lt;h2 id=&quot;results-from-lemons-to-lemonade&quot;&gt;Results: From lemons to lemonade&lt;/h2&gt;
&lt;p&gt;The results of these improvements are impressive:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;firmware&lt;/th&gt;
&lt;th&gt;p/s&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;lemons&lt;/td&gt;
&lt;td&gt;1.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;packets &amp;amp; sorting&lt;/td&gt;
&lt;td&gt;5.57&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;unlocked&lt;/td&gt;
&lt;td&gt;10.3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Here, ‘lemons’ is the original firmware; ‘packets &amp;amp; sorting’ is after sorting, and ‘unlocked’ is me addressing the concurrency issues, by deleting the locks. &lt;code&gt;p/s&lt;/code&gt; stands for packets per second for strong signals in this case. This is just a single measure for strong close signal bandwidth, but the new firmware improves in all categories we measured. &lt;a href=&quot;#fn10&quot; class=&quot;footnote-ref&quot; id=&quot;fnref10&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;10&lt;/sup&gt;&lt;/a&gt; I did this in about three weeks of work. Because we’re going so fast, there are more improvements in the pipeline since we’ve time, such as using Protobuf instead of JSON, which will increase throughput, and tweaking Bluetooth parameters causing a higher capture rate, which I may describe in a later post. After we’ve done all that, we can say we’ve made lemonade!&lt;/p&gt;
&lt;p&gt;It’s funny that I was unsure about starting with firmware changes or even suggesting it. I was outright anxious about doing these concurrency updates. They all turned out to have outsized impacts on the entire tech stack. We’re winning now. This company may very well become a logistics company due to these calculated gambles. Do you have any stories about professional, calculated gambles? Please let me know in the comments; I’d love to know 😀&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;Note that there would be many Bluetooth tags all emitting signals, so even if the scanner could catch 5 a second, it had to send the right signal as well! Supposedly the Bluetooth tags were sending out a signal once every 300 milliseconds. so what happened to all these signals? What would happen in this 2 minute interval is that it’d pick up the wrong signals, of stuff just laying around, and send those over!&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;For particle tracker one, you have to screw it open, and there is a mode and reset button, hold the mode button, then tap the reset button, once it starts flashing green release mode, this will allow you to put new firmware on it again via usb.&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;Which is starkly different from my haskell workflow of just writing everything you want in one go, solve a metric ton of compile errors and having a functioning program. This Made me realize how spoiled I am.&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;Apparantly you can use some c++ standard library function, trying to use a custom sort from the internet also cost me days. 😅&lt;a href=&quot;#fnref4&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn5&quot;&gt;&lt;p&gt;My colleague menioned they asked to sort the signals from the original contractors, but they never did this.&lt;a href=&quot;#fnref5&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn6&quot;&gt;&lt;p&gt;There was no reason for this and &lt;a href=&quot;https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables&quot;&gt;it’s&lt;/a&gt; &lt;a href=&quot;https://stackoverflow.com/a/485020&quot;&gt;suspicious&lt;/a&gt;.&lt;a href=&quot;#fnref6&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn7&quot;&gt;&lt;p&gt;This explains the fast turnover time, I just fixed obvious glaring problems, which you can see by reading code and trying to figure out what it does.&lt;a href=&quot;#fnref7&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn8&quot;&gt;&lt;p&gt;Because the code segfaults and red blinking light is all you get.&lt;a href=&quot;#fnref8&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn9&quot;&gt;&lt;p&gt;Not to be confused with &lt;code&gt;void&lt;/code&gt;, which is just an empty return type, or &lt;code&gt;Void&lt;/code&gt; in haskell, which means no value will ever be that.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode c&quot;&gt;&lt;code class=&quot;sourceCode c&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;struct&lt;/span&gt; QueueItem &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;#cb5-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;BleAddress address&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb5-3&quot;&gt;&lt;a href=&quot;#cb5-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;uint8_t&lt;/span&gt; advertiseData&lt;span class=&quot;op&quot;&gt;[&lt;/span&gt;BLE_MAX_ADV_DATA_LEN&lt;span class=&quot;op&quot;&gt;];&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb5-4&quot;&gt;&lt;a href=&quot;#cb5-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;size_t&lt;/span&gt; count&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb5-5&quot;&gt;&lt;a href=&quot;#cb5-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;int8_t&lt;/span&gt; rssi&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-6&quot;&gt;&lt;a href=&quot;#cb5-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A struct is a continuous memory block.[^know-why] &lt;code&gt;BleAddress&lt;/code&gt; can be inserted because it is also a simple struct with no pointers. I had to make some more modifications to support the primitives in the &lt;code&gt;Eddystone&lt;/code&gt; class. [^class] but once this was done it worked.&lt;a href=&quot;#fnref9&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn10&quot;&gt;&lt;p&gt;In the force update activity for examle, by just tapping the sensor to a Bluetooth tag we managed to increase success rate from 20% to about 90%. [^doesntwork] The system only managed to work without doing this by having long exposure to signals, but now we also support these quick exposures. Which makes the entire stack more robust.&lt;a href=&quot;#fnref10&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Analyzing Haskell stability</title>
    <link href="https://jappieklooster.nl/analyzing-haskell-stability.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2024-07-30:/analyzing-haskell-stability.html</id>
    <published>2024-07-30T15:00:00Z</published>
    <updated>2024-07-30T15:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;figure&gt;
&lt;img src=&quot;/images/2024/stability.webp&quot; alt=&quot;Stability - according to gpt4o&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Stability - according to gpt4o&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I joined the &lt;a href=&quot;https://github.com/haskellfoundation/stability&quot;&gt;Haskell Stability Working Group&lt;/a&gt; about a year ago. I was freshly scarred from a GHC upgrade, so I decided to try improving the situation. I think my first contribution was making an example for &lt;a href=&quot;https://github.com/jappeace/haskell-nightly&quot;&gt;GHC nightly builds&lt;/a&gt; on GitHub Actions. This allows&lt;/p&gt;</summary>
    <content type="html">&lt;figure&gt;
&lt;img src=&quot;/images/2024/stability.webp&quot; alt=&quot;Stability - according to gpt4o&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Stability - according to gpt4o&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I joined the &lt;a href=&quot;https://github.com/haskellfoundation/stability&quot;&gt;Haskell Stability Working Group&lt;/a&gt; about a year ago. I was freshly scarred from a GHC upgrade, so I decided to try improving the situation. I think my first contribution was making an example for &lt;a href=&quot;https://github.com/jappeace/haskell-nightly&quot;&gt;GHC nightly builds&lt;/a&gt; on GitHub Actions. This allows downstream&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; maintainers to build GHC nightly to spot issues early.&lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Recently, we’ve been curious about what Haskell ecosystem and GHC changes cause the most breakage. A suggestion was made to do a quantitative analysis of “head.hackage”. “head.hackage” is a repository of patches for Hackage. GHC engineers use these to test out new GHC builds on a wide range of Hackage packages without having to upstream&lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; a patch, which can take time. Instead, they can put the patch in “head.hackage” and immediately test it on a wide range of packages. We can analyze this repository of patches and categorize them according to the &lt;a href=&quot;https://docs.google.com/document/d/1sX_rXHx8Mj3Kae9GalR2BwZ5-xzl7UpnpMBwl4dqsWY/edit&quot;&gt;GHC Stability State of Play&lt;/a&gt; I volunteered for that effort. Here is a preliminary result of the “head.hackage” patches required to make around 485 packages&lt;a href=&quot;#fn4&quot; class=&quot;footnote-ref&quot; id=&quot;fnref4&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; build.&lt;/p&gt;
&lt;iframe style=&quot;width:100%; height:20em;&quot; src=&quot;https://docs.google.com/spreadsheets/d/e/2PACX-1vQR7N5UxVMFi8gGXkfowWceSMnxVAEtmRBjjdYxcEzyEJQh55ykfnz4hAR7xeJclnp5wiZh80HTG5f6/pubhtml?widget=true&amp;amp;headers=false&quot;&gt;
&lt;/iframe&gt;
&lt;p&gt;From this, we can see that we’re not doing too bad for stability in GHC directly. Many of these patches are for older changes for example. Although, from first hand experience, I know we can definitely improve! We’re going to extend this work by labeling the exact cause of breakage for each patch (many do overlap). This will allow us to see more clearly which changes caused most issues and help us prevent similar situations in the future.&lt;/p&gt;
&lt;p&gt;Do you have any opinions on this document? do you feel stability could be better? or do you have a specific frustration which grinds your gears around stability? Please reach out! We’re always interested in hearing from the community and are in fact actively recruiting members. You don’t need to join; you can also email or use the comment box below.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;Downstream in this case means people who use GHC and are dependent on it.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;At first, I thought these mechanisms were great. However, at some point upstream GHC started breaking for some reason and I learned that the availability was ‘best effort’, causing me a bunch of issues. So I turned it off. But I applied these “GitHub Actions” techniques I learned for various other repositories. I learned that for projects that have little activity, github likes to disable automations. Since 99% of my projects are like that, it essentially makes all of GitHub Actions kinda useless for me. I had a pretty bad experience with GitHub Actions before all this, and this made me even more estranged. It’s unreliable compared to the Nix CI pipelines I’m used to.&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;Upstreaming is the process of sending a patch to the “maintainers” of an open-source project. The maintainers will then make the patch ‘official’ by merging it. In principle, the process is simple, but in practice, the burden of proof (especially for larger projects) is on the person who submitted the patch. They have to convince the maintainers that the patch is useful, which takes time in the form of communication.&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;The estimate of 485 packages is done based on this &lt;a href=&quot;https://grafana.gitlab.haskell.org/d/7T7oEMlMz/head-hackage-performance?orgId=2&amp;amp;viewPanel=3&amp;amp;var-packages=All&quot;&gt;Grafana dashboard&lt;/a&gt;. The number changes over time. this measurement was made on 2024-07-28.&lt;a href=&quot;#fnref4&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Cabal exact printing</title>
    <link href="https://jappieklooster.nl/cabal-exact-printing.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2024-05-12:/cabal-exact-printing.html</id>
    <published>2024-05-12T18:00:00Z</published>
    <updated>2024-05-12T18:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;For a long time, I’ve been annoyed that &lt;a href=&quot;https://www.haskell.org/cabal/&quot;&gt;cabal&lt;/a&gt; tells you to add modules to your cabal file. It can detect missing modules, but won’t automatically add them. This is not a big deal for a single module, but if you like splitting code into many small modules, for example&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;For a long time, I’ve been annoyed that &lt;a href=&quot;https://www.haskell.org/cabal/&quot;&gt;cabal&lt;/a&gt; tells you to add modules to your cabal file. It can detect missing modules, but won’t automatically add them. This is not a big deal for a single module, but if you like splitting code into many small modules, for example because you like &lt;a href=&quot;https://www.parsonsmatt.org/2019/11/27/keeping_compilation_fast.html#the-projecttypes-megamodule&quot;&gt;fast compile times&lt;/a&gt;, then any refactor may cause many of these messages to appear, which becomes tedious to manage.&lt;/p&gt;
&lt;div style=&quot;width:100%; text-align:center;&quot;&gt;
&lt;p&gt;&lt;img style=&quot;width:50%;&quot; alt=&quot;exact print image&quot; src=&quot;/images/2024/exact-print.webp&quot; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Currently, if you build a project with an extra module not listed in your cabal file, GHC emits a warning:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;no location info&amp;gt;: error: [-Wmissing-home-modules, -Werror=missing-home-modules]
    These modules are needed for compilation but not listed in your .cabal file&amp;#39;s other-modules: 
        X&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’d say, why doesn’t cabal just add this module to the cabal file? Well, it can’t. Cabal is currently only able to parse Cabal files, and print them back out in a mangled&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; form. There are other programs providing module detection &lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;, but nothing is integrated in cabal itself. Anyway, one day I was lamenting this problem on the internet and I was told by a forum user&lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; that this is in fact the &lt;a href=&quot;https://github.com/haskell/cabal/issues/7544&quot;&gt;cabal exact print&lt;/a&gt; issue. GHC is &lt;a href=&quot;https://github.com/alanz/ghc-exactprint&quot;&gt;already able&lt;/a&gt; to do this for Haskell code, and &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/wikis/api-annotations#in-tree-exact-printing-annotations&quot;&gt;defines&lt;/a&gt; it as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Taking an abstract syntax tree (AST) and converting it into a string that looks like what the user originally wrote is called exact-printing. An exact-printed program includes the original spacing and all comments.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In any case, after some exploratory discussion in that thread, I got a maintainer to &lt;a href=&quot;https://github.com/haskell/cabal/pull/9436#issuecomment-1809209581&quot;&gt;endorse&lt;/a&gt; an &lt;a href=&quot;https://github.com/haskell/cabal/pull/9436#issue-1989616367&quot;&gt;approach I made&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Previous attempts were &lt;a href=&quot;https://github.com/haskell/cabal/pull/7626&quot;&gt;abandoned&lt;/a&gt;. Or they revolved around creating a seperate AST&lt;a href=&quot;#fn4&quot; class=&quot;footnote-ref&quot; id=&quot;fnref4&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt;, which was against maintainer recommendation, and then &lt;a href=&quot;https://github.com/haskell/cabal/pull/9385&quot;&gt;abandoned&lt;/a&gt;. I’m doing a fully integrated design around the &lt;code&gt;parseGenericPackageDescription&lt;/code&gt; function.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;parseGenericPackageDescription ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ByteString&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;#cb3-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                               &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ParseResult&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;GenericPackageDescription&lt;/span&gt; &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This function takes a &lt;code&gt;ByteString&lt;/code&gt; (cabal file), and returns a &lt;code&gt;GenericPackageDescription&lt;/code&gt;. Which is the data type the rest of cabal works with. This is the cabal equivalent of an AST. To make sure the changes I make are helping, I setup several round trip test concerning the various properties we want see exact printed. For example, I’ll add a cabal &lt;a href=&quot;https://github.com/haskell/cabal/blob/a75d51b8921f30ec24414f7a3413afc0e0fac111/Cabal-tests/tests/ParserTests/exactPrint/comments.cabal&quot;&gt;file&lt;/a&gt; with comments:&lt;/p&gt;
&lt;pre class=&quot;cabal&quot;&gt;&lt;code&gt;cabal-version:           3.0
name:                    two-sections 
version:                 0
synopsis:                The -any none demo
build-type:              Simple

                         -- my awesome
-- library
library 
  default-language:  Haskell2010
  exposed-modules:   AnyNone
  build-depends:     base &amp;lt;5
                    , containers
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We put that file through &lt;code&gt;parseGenericPackageDescription&lt;/code&gt;, put the result of that function called &lt;code&gt;GenericPackageDescription&lt;/code&gt; into the &lt;code&gt;exactPrint&lt;/code&gt; function, and it should be the &lt;a href=&quot;https://github.com/haskell/cabal/pull/9436/files#diff-81e14d1d71534933570bc079db1bbd5795b7b88ec79da5462d586bd8ea637c31R82&quot;&gt;&lt;em&gt;exact&lt;/em&gt; same&lt;/a&gt;. By doing this we should theoretically be allowed to modify &lt;code&gt;GenericPackageDescription&lt;/code&gt; however we please, and get the result printed, which is a step towards solving our initial module not listed problem (and &lt;a href=&quot;https://github.com/haskell/cabal/labels/exact-print&quot;&gt;several others&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The implementation itself is simple. We add a &lt;a href=&quot;https://github.com/haskell/cabal/pull/9436/files#diff-73c00fc0bacfac2e46beb6b5fafba1886f0e32e8678b5173347acfd7ec8aef05R127&quot;&gt;field&lt;/a&gt; to &lt;code&gt;GenericPackageDescription&lt;/code&gt; with all the exact print data, which we access trough &lt;code&gt;Map&lt;/code&gt;’s. The key is a new concept called a &lt;code&gt;NameSpace&lt;/code&gt;. Values are &lt;code&gt;ExactPostions&lt;/code&gt; for example. I modified the pretty printer to first try and get an exact position, before falling back to pretty printing. This instantly solved the tests for sections. Which was a good result!&lt;/p&gt;
&lt;p&gt;However, there is still a long list of features we need to support, such as comments, common stanzas, better comma support, and conditional branches. Exact printing comments is hard because currently cabal filters them instead of parsing them. so the parser needs to be modified as well. Fortunately someone has already done some &lt;a href=&quot;https://github.com/haskell/cabal/pull/9436/commits/d752e49e526a377f1ec96a37660e0fd9b88cb5e0&quot;&gt;preliminary work&lt;/a&gt; on that, unfortunately it breaks my existing tests. Common stanzas allow users to declare some shared stanza, such as ghc-options or build depends fields, and re-use them across various targets such as the library or executable. This is also hard because the common stanzas are currently just absorbed into whatever &lt;a href=&quot;https://github.com/haskell/cabal/pull/9436/files#diff-39a353df50e7eed47b5958c6025b67b06fac735a8b5b994c1464d6fd84df745eR696&quot;&gt;they’re imported&lt;/a&gt;, they don’t exist in the &lt;code&gt;GenericPackageDescription&lt;/code&gt; at all! Exact printing comma support seems a bit strange, but you can put commas in many different places and still have a valid cabal file. These locations need to be parsed and tracked somehow. I’ve not even spoken about conditional branches yet, which I’ve not thought about much, however the point is that there is a lot to support!&lt;/p&gt;
&lt;p&gt;In general the issue why this exact printing is so hard is because cabal has a lot of features, all needing to be supported. And every new feature added will not have exact printing support until &lt;em&gt;some&lt;/em&gt; solution gets merged. So over time we can expect exact printing to become even harder to implement.&lt;/p&gt;
&lt;p&gt;Why I’m writing this instead of just implementing exact print? Back in November, I implemented some initial solution in anger, and with a draft PR created, my anger had all but dissipated. With clarity of mind, I realized spending all my free time implementing this feature isn’t sustainable. I’d burn out at that rate. Essentially I’m looking for a way to make this more sustainable.&lt;/p&gt;
&lt;p&gt;A possibility is to create a Haskell &lt;a href=&quot;https://github.com/haskellfoundation/tech-proposals/blob/main/proposals/templates/CommunityProject.md&quot;&gt;tech proposal&lt;/a&gt;. This is a funding mechanism for long-standing issues in the Haskell community. With funding I could trade hours in my day job for hours working on this particular issue, without losing anything on mental health. Currently the issue is that these proposals look like &lt;a href=&quot;https://github.com/haskellfoundation/tech-proposals/blob/main/proposals/052-cryptography-leg-1.md&quot;&gt;a lot of work&lt;/a&gt;. And I’m not sure how much budget is even available for a project like this. So in essence this blog-post is a preproposal, to see what people think of it without going all the way.&lt;/p&gt;
&lt;p&gt;Another possibility is recruiting volunteers. In general, however they’d run into the same issue I had! However I do think if I’d trade some money for some helping hands then this could work. The tests can be solved in parallel, a single person could work on comments, and another on common stanzas for example. But would this be allowed by the tech proposal system?&lt;/p&gt;
&lt;p&gt;I believe this exact printing is solvable problem. However I lack the resources to solve this personally. I think a tech proposal may be able to provide said resources. Although the process involved is daunting enough for me to first ask the community, do people want this? Please reply if you’re bothered by this, or have any comments on my approach.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;you can see this mangling by running &lt;code&gt;cabal format&lt;/code&gt; on a cabal file, the issues I saw were:
&lt;ol&gt;
&lt;li&gt;
Delete all comments
&lt;/li&gt;
&lt;li&gt;
Merges any &lt;code&gt;common&lt;/code&gt; stanza into wherever it was imported.
&lt;/li&gt;
&lt;li&gt;
Change line ordering
&lt;/li&gt;
&lt;li&gt;
Change spacing (although perhaps to be expected from a formatter)
&lt;/li&gt;
&lt;/ol&gt;
&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;We have a whole host of projects that re-implement this specific functionality. for example have:
&lt;ul&gt;
&lt;li&gt;
&lt;a href=&quot;https://github.com/sol/hpack&quot;&gt;hpack&lt;/a&gt;,
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://github.com/kowainik/autopack&quot;&gt;autopack&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://github.com/phadej/cabal-fmt&quot;&gt;cabal-fmt&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://taylor.fausak.me/2024/02/17/gild/&quot;&gt;gild&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;            Of course many of these projects do more then just module expension.
            hpack provides a completly different cabal file layout for exampe,
            cabal-fmt and gild are formatters for cabal file.
            Only auto-pack just does this one feature.
            However, since all these programs implement this functionality,
            there is clearly demand for it.
            no-one has attempted to centralize it yet however.&lt;/code&gt;&lt;/pre&gt;
&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;They’re a self identified milk enthusiast, whatever that means.&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;AST: Abstract Syntax Tree, a tree representation of the structure of code, which helps the system understand and manipulate code.&lt;a href=&quot;#fnref4&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Announcement: Updated Esqueleto text-search &amp; PostGIS bindings</title>
    <link href="https://jappieklooster.nl/announcement-updated-esqueleto-text-search-postgis-bindings.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2024-02-25:/announcement-updated-esqueleto-text-search-postgis-bindings.html</id>
    <published>2024-02-25T15:01:00Z</published>
    <updated>2024-02-25T15:01:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;I’ve updated the esqueleto bindings for &lt;a href=&quot;https://hackage.haskell.org/package/esqueleto-textsearch&quot;&gt;esqueleto-textsearch&lt;/a&gt; to include a &lt;a href=&quot;https://hackage.haskell.org/package/esqueleto-textsearch#tutorial&quot;&gt;tutorial&lt;/a&gt; and &lt;a href=&quot;https://hackage.haskell.org/package/esqueleto-textsearch-1.1.4/docs/Database-Esqueleto-TextSearch.html&quot;&gt;documentation&lt;/a&gt; so it no longer requires guesswork. Furthermore I’ve also created new &lt;a href=&quot;https://hackage.haskell.org/package/esqueleto-postgis&quot;&gt;esqueleto bindings for PostGIS&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2024/esqueleto.webp&quot; alt=&quot;esqueleto&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;esqueleto&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://hackage.haskell.org/package/esqueleto&quot;&gt;Esqueleto&lt;/a&gt; is a more advanced query library that builds on top of the &lt;a href=&quot;https://hackage.haskell.org/package/persistent&quot;&gt;persistent&lt;/a&gt; ORM&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;. &lt;a href=&quot;https://rachbelaid.com/postgres-full-text-search-is-good-enough/&quot;&gt;Postgres text search&lt;/a&gt;&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;I’ve updated the esqueleto bindings for &lt;a href=&quot;https://hackage.haskell.org/package/esqueleto-textsearch&quot;&gt;esqueleto-textsearch&lt;/a&gt; to include a &lt;a href=&quot;https://hackage.haskell.org/package/esqueleto-textsearch#tutorial&quot;&gt;tutorial&lt;/a&gt; and &lt;a href=&quot;https://hackage.haskell.org/package/esqueleto-textsearch-1.1.4/docs/Database-Esqueleto-TextSearch.html&quot;&gt;documentation&lt;/a&gt; so it no longer requires guesswork. Furthermore I’ve also created new &lt;a href=&quot;https://hackage.haskell.org/package/esqueleto-postgis&quot;&gt;esqueleto bindings for PostGIS&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2024/esqueleto.webp&quot; alt=&quot;esqueleto&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;esqueleto&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://hackage.haskell.org/package/esqueleto&quot;&gt;Esqueleto&lt;/a&gt; is a more advanced query library that builds on top of the &lt;a href=&quot;https://hackage.haskell.org/package/persistent&quot;&gt;persistent&lt;/a&gt; ORM&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;. &lt;a href=&quot;https://rachbelaid.com/postgres-full-text-search-is-good-enough/&quot;&gt;Postgres text search&lt;/a&gt; brings &lt;a href=&quot;https://en.wikipedia.org/wiki/Elasticsearch&quot;&gt;Elasticsearch&lt;/a&gt; like functionality to Postgres. &lt;a href=&quot;https://postgis.net/&quot;&gt;PostGIS&lt;/a&gt; is a spatial database extension for Postgres. This allows querying on longitude and latitude for example, or any geometry. As part of postgres it allows mixing normal relational data with space and geometry, which makes space itself relational!&lt;/p&gt;
&lt;p&gt;Roughly four years ago I had drafted out an implementation for the admin pages for some company. This was part of my “trial” 2 days, where you just work as a “technical interview”. &lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; Ironically the admin pages ended up having far better search than the main app, unfortunately, implementing proper text-search to the main app was never prioritized. A colleague of mine had ported that to the &lt;a href=&quot;https://hackage.haskell.org/package/esqueleto-textsearch&quot;&gt;current library&lt;/a&gt;. Recently I needed this again. However, I completely had forgotten how it worked and there was essentially &lt;a href=&quot;https://hackage.haskell.org/package/esqueleto-textsearch-1.0.0.3/docs/Database-Esqueleto-TextSearch-Language.html&quot;&gt;no documentation&lt;/a&gt;. &lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; Since I was somehow the maintainer of this package I decided to just fix this for all Haskellers.&lt;/p&gt;
&lt;p&gt;PostGIS has a different motivation. My current contract is about finding stuff. Now I could do this with some geometry library in pure haskell. However, considering most logic is already in the database, I decided it was worth a try to see if PostGIS would be a good fit. There was already some existing art done, such as &lt;a href=&quot;https://hackage.haskell.org/package/wkt-geom-0.0.12/docs/Data-Ewkb.html#v:parseHexByteString&quot;&gt;reading&lt;/a&gt; from the database, but there was no off-the-shelf, functional writing. I initially handcrafted some haphazard persistent instances to see if a full solution was feasible. It worked, and one interesting outcome is that I could combine this PostGIS implementation with text-search! For example, we’ve named locations on a map, and objects within the database have some point on the map, we can now search for some location on the map and find the objects through normal full-text search. The database does all the thinking. Because this worked so well, I got motivated to do the full bindings for PostGIS, and prevent the issue I just had with text-search.&lt;/p&gt;
&lt;p&gt;I’m slowly transforming into a database engineer 😅. Anyway, everyone should try these libraries out! You’re in space after all, and you lose stuff all the time, go get searching in space! Let me know if you’ve any comments or suggestions. Furthermore, let me know if you need help with database woes, I’m becoming quite good at this.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;Object relational mapping&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;I perform way better in such a situation than a take-home test, because it’s incredibly hard for me to get motivated to do throw away work, but here I did something useful.&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;Note that the hackage upload was also done by me, because my dear colleague had ported it to a library which wasn’t even published! It was just some github repository. After a couple years I decided to just upload it, right before I jumped ship to another company.&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Lessons from creating a vacation rental.</title>
    <link href="https://jappieklooster.nl/lessons-from-creating-a-vacation-rental.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2024-01-02:/lessons-from-creating-a-vacation-rental.html</id>
    <published>2024-01-02T19:00:00Z</published>
    <updated>2024-01-02T19:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;p&gt;&lt;a href=&quot;https://www.airbnb.nl/h/jappie-aruba&quot;&gt;Villa Katalina in aruba~ is online&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2024/katalina.jpeg&quot; alt=&quot;pic of the house&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;pic of the house&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;You can book &lt;a href=&quot;https://www.airbnb.nl/h/jappie-aruba&quot;&gt;this wonderful rental now!&lt;/a&gt; This is the rebranded &lt;a href=&quot;%7Bfilename%7D/summerhouse-paradis.md&quot;&gt;summerhouse Paradis&lt;/a&gt;. It’s a villa that can host up to 8 guests, located in Aruba. I think this rental project is slowly turning out to be successful,&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://www.airbnb.nl/h/jappie-aruba&quot;&gt;Villa Katalina in aruba~ is online&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2024/katalina.jpeg&quot; alt=&quot;pic of the house&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;pic of the house&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;You can book &lt;a href=&quot;https://www.airbnb.nl/h/jappie-aruba&quot;&gt;this wonderful rental now!&lt;/a&gt; This is the rebranded &lt;a href=&quot;%7Bfilename%7D/summerhouse-paradis.md&quot;&gt;summerhouse Paradis&lt;/a&gt;. It’s a villa that can host up to 8 guests, located in Aruba. I think this rental project is slowly turning out to be successful, but it wasn’t easy. I went into this project knowing full well there would be trouble, and boy, there was trouble. I’ll list the issues and lessons learned from doing this for future me. I may wish to do this again; it was a fun ride. If you’re interested in doing something similar, I think this blog post is useful.&lt;/p&gt;
&lt;p&gt;The prices for real estate were really good in Aruba compared to the Netherlands at the time of buying; I got about double of what I could expect in the Netherlands. Since my parents already have an &lt;a href=&quot;https://www.casaaruba.info/&quot;&gt;investment property&lt;/a&gt; in Aruba, it seemed relatively easy to set up, not to say it was easy. Another reason for doing this was the low interest rates, which looked like attractive leverage. Furthermore, I already had experience with running an Airbnb in my own home, so I felt somewhat confident I could make this work. Because my own house is not in a touristic area at all, but Aruba is. I’d be lying if I said this only done for financial reasons. Ego played a large part in deciding to do this as well. For one, not being completely dependent on a single source of income allows me to take more professional risks and become more productive as a result. The other reason is bragging rights, not that I wish to brag, but the only way to be humble is to have something to brag about &lt;a href=&quot;https://www.youtube.com/watch?v=S-huj6EL3A4&quot;&gt;and not do that&lt;/a&gt;. This is so hard.&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; 😬&lt;/p&gt;
&lt;p&gt;I considered many other properties before settling on this one; at first, I wanted to build a new place. This made sense to me since labor costs are low in Aruba. However, my father strongly urged against that, citing many experiences of even the smallest jobs going wrong. You have to watch contractors like a hawk if you want to do this. I experienced such issues as well with some contractors while doing the pool house. For example, the fuse switch in the pool house couldn’t switch off because the plastic door was jammed too close to the switches, giving no space to move. If you’re considering building on Aruba, keep in mind you have to be there, or have someone trustworthy there, and watch the contractors.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2024/jappie-dig.jpg&quot; alt=&quot;jappie digs the pool&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;jappie digs the pool&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The amount of corruption or incompetence&lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; on Aruba is rather staggering. For example, the notary &lt;a href=&quot;https://www.johnsonnotary.com/&quot;&gt;Johnson and Johnson&lt;/a&gt;, took ages to close when I was buying the place. The closing date was at the end of July; I assumed it would be done before that time, but we closed in October. I was familiar with Aruba’s culture of taking things slowly, but I didn’t expect things to take this long! What I could have done differently in this case is contact the notary more often for progress updates. I think they just forgot about this deal or something. I was even told this was exceptionally slow. Because the closing took so long, I essentially missed out on opportunity costs. I could have opened the Airbnb two months earlier, in March instead of May, which means I missed all that income.&lt;/p&gt;
&lt;p&gt;Another example of incompetence I’m currently facing is with the power company &lt;a href=&quot;https://www.elmar.aw/&quot;&gt;Elmar&lt;/a&gt;, and &lt;a href=&quot;https://mistergreenaruba.com/&quot;&gt;Mr. Green&lt;/a&gt; solar services. The solar panels were installed on 15 August, and I was promised they could at least be turned on from that point, subtracting power generation from my usage. It’s now January, and this still hasn’t happened. Even after that, the excess is still given away to Elmar for free, after some “mythical” inspection which has to take at least 6 months. This delay is costing me the full power bill, which is 250 euros a month. I have no idea why it takes this long; it’s not a big island! Having learned from my Johnson experience, I’m contacting Mr. Green weekly.&lt;/p&gt;
&lt;p&gt;What also caught me off guard was the fluctuation in exchange rates, which caused a lot of stress. The euro fell sharply against the dollar while I was waiting for the deal to close, but the listing price was denominated in dollars, and I had euros saved up! This made the property effectively 10% more expensive. Considering the price was 180,000 dollars, this cost me 18,000. I must admit, I shed a tear over this. In the future, I should put the closing money in an account of the same currency as soon as I sign.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2023/course.png&quot; alt=&quot;course of euro/dollar&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;course of euro/dollar&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;However, what I’m really happy with is not going into hyper debt. My father, who financed half of this investment property&lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; with a mortgage-like loan, recommended I look at more expensive properties. So, I was looking at properties around 400k at first, however, I decided to go with a cheaper option instead, at 180k, even though the lender would have agreed to the more expensive option. I’m really happy I did this because during the renovation, I decided that a pool would drastically increase the appeal, allowing me to charge much more rent &lt;a href=&quot;#fn4&quot; class=&quot;footnote-ref&quot; id=&quot;fnref4&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt;, but this would require another 30k investment. This was still possible because the monthly payments weren’t as high yet. The biggest advantage of these more expensive properties was their proximity to the beach. However, I think this is somewhat overvalued, because public transit is poor in Aruba, so unless you’re right on the beach, tourists are going to have to rent a car anyway. In this regard, my more budget-friendly stay offers a lot of value to tourists.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2024/skilled.jpeg&quot; alt=&quot;pool&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;pool&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;After handover, when doing some renovations, many people will recommend extending the scope of a project significantly. This can come from friends and family. I had discussions about adding more walls for additional bedrooms, or installing doors, or various other changes, but most of these wouldn’t be very profitable. However, they would extend the timeline, so I refused most of these requests. The first guest &lt;a href=&quot;https://www.airbnb.nl/progress/reviews/details/921014041531665037&quot;&gt;recommended&lt;/a&gt; me to put a fence between the pool and the patio, to ensure the kids could play safely outside. This was a minor change overall, and could happen with other guests staying there. This change solved a real issue that this guest, and by extension other guests, were concerned about. None of my family or friends had suggested such a change, as nobody had stayed at the place with kids. I kept focus on solving all these problems guests highlighted in reviews, when they were reasonable, such as “we miss wine glasses”, “we need trash cans in the bathrooms”, “we don’t have oven-ready pots and pans, but there is an oven”. Some requests were impractical, like “move the pool behind the house”, and I ignored those. Addressing these issues usually cost less than 100 euros, and even the fence was done for less than 1000 euros. Compared to the amount I spent on the pool and the house itself, this was minor and a fixed costs. However, after addressing these issues after the first few visits, the complaints stopped and people began giving me consistent 5-star reviews, even though the price had increased significantly in December. I learned that the difference between a good stay and a great stay lies in many small details, which are hard to anticipate. Guests will share their problems if you ask. Recommendations from family and friends during renovations need to be carefully evaluated, as they’re not always beneficial.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2024/fence.jpeg&quot; alt=&quot;the fence is shown behind the pool&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;the fence is shown behind the pool&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I learned that people who are good at one job may underperform if you let them do a slightly different job. For example, the guy who built the wall (Cesar) and the tiling around the pool did some great jobs, but then I let him install a shower, and he inadvertently installed the faucet upside down. It’s still in this awkward position. Aruban contractors often will say they can do something, even though it may be their first time doing such a job. One has to be careful about this. I like this particular contractor, however, because he can’t speak English and I find the non-verbal communication rather amusing. So, I’d hire him again, but not for showers!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2024/douche.jpeg&quot; alt=&quot;shower flipped&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;shower flipped&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Knowing skilled people is something that is difficult for newcomers in Aruba. I got incredibly lucky in that regard, considering my parents had already sifted through so many contractors for their &lt;a href=&quot;https://www.casaaruba.info/&quot;&gt;Casa Aruba&lt;/a&gt; rental property. For example, I was able to hire a &lt;a href=&quot;https://www.facebook.com/steigerhoutaruba/&quot;&gt;local carpenter&lt;/a&gt; to redo the entire kitchen for a third of the price I would have had to pay if I had used a European kitchen supplier. The kitchen looks better, too! The entire house now has this scaffolding wood style, giving it a robust and cozy ambiance.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2024/kitchen-2.jpeg&quot; alt=&quot;second kitchen pick&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;second kitchen pick&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I was also blessed with the support of my parents. Besides financing, they supported me with the paintwork, and there was a lot of it. Without their help, I probably would have spent another 8k on that and ended up with a worse result.&lt;/p&gt;
&lt;p&gt;I’m not sure if it was financially worth it. Intuitively, I think it was, but I still need to run the numbers more thoroughly once the first year is finished. My preliminary observations suggest I need to make more than 1500 euros a month to turn a profit, and more than 3000 euros a month to cover mortgage payments as well. I have a strict payback schedule, because I didn’t like the high interest rate from the private market, but this will be completed in 6 years. It’s difficult to measure if it’s “worth it,” because the first few months of this project were naturally the worst I could have had. I had no reviews so I had to compensate by lowering the price. Furthermore, things like solar panels and my custom &lt;a href=&quot;https://github.com/jappeace/rentals/&quot;&gt;rental booking&lt;/a&gt; site are still not operational&lt;a href=&quot;#fn5&quot; class=&quot;footnote-ref&quot; id=&quot;fnref5&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt;. The solar panels should reduce the electric bill from roughly 250 euros to close to 0, and the rental booking website eliminates the need for Airbnb, which takes 17% cut of bookings.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2024/bed.jpeg&quot; alt=&quot;bed&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;bed&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Ironically, despite all the setbacks, I may do this again. Seeing the house come to life, reading all the reviews from people, and experiencing their appreciation is fantastic. However, I’d like to confirm first if it’s financially worth it. After it has been open for a year, I plan to create an private overview of this investment, detailing how much it brought in and how much I spent on it. Furthermore, I currently simply do not have the cash to set up another one. I feel I’m quite good at this. However, if you happen to run a rental and have ideas for improvement, please let me know in the comments!&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;Of course, I did tell people about the BnB I bought. One could even say this post is a giant brag, but hey, I’m not forcing you to read this, my dear reader.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;I say incompetence because, according to &lt;a href=&quot;https://en.wikipedia.org/wiki/Hanlon%27s_razor&quot;&gt;Hanlon’s razor&lt;/a&gt;, it’s usually just that.&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;He got a 5% interest rate while other mortages were going around for 1.5%. So it’s not like I got a handout.&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;Say 50% more.&lt;a href=&quot;#fnref4&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn5&quot;&gt;&lt;p&gt;If it is operational this &lt;a href=&quot;https://rental.jappie.me&quot;&gt;link&lt;/a&gt; should work.&lt;a href=&quot;#fnref5&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Follow Up on the Follow-Up</title>
    <link href="https://jappieklooster.nl/follow-up-on-the-follow-up.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2023-11-11:/follow-up-on-the-follow-up.html</id>
    <published>2023-11-11T00:00:00Z</published>
    <updated>2023-11-11T00:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;style&gt;
img[src=&quot;/images/2023/follow-up.png&quot;]{
  height: 20em;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2023/follow-up.png&quot; alt=&quot;Reflective&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Reflective&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This is a follow-up on the &lt;a href=&quot;%7Bfilename%7D/followup-releasing.md&quot;&gt;follow up&lt;/a&gt; of &lt;a href=&quot;%7Bfilename%7D/releasing-software.md&quot;&gt;release rodeo&lt;/a&gt;. Okay, I should stop doing these, however, I thought the situation was a bit too ironic not to record. On my final week working for that company &lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;, the product manager involved&lt;/p&gt;</summary>
    <content type="html">&lt;style&gt;
img[src=&quot;/images/2023/follow-up.png&quot;]{
  height: 20em;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2023/follow-up.png&quot; alt=&quot;Reflective&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Reflective&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This is a follow-up on the &lt;a href=&quot;%7Bfilename%7D/followup-releasing.md&quot;&gt;follow up&lt;/a&gt; of &lt;a href=&quot;%7Bfilename%7D/releasing-software.md&quot;&gt;release rodeo&lt;/a&gt;. Okay, I should stop doing these, however, I thought the situation was a bit too ironic not to record. On my final week working for that company &lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;, the product manager involved found my original blog post!&lt;/p&gt;
&lt;p&gt;A colleague and I were discussing some performance degradation, and I brought up the &lt;a href=&quot;%7Bfilename%7D/undeadlock-event-source.md&quot;&gt;event sourcing&lt;/a&gt; post, because this company also used event sourcing and it was maybe related. However the PM apparently followed that link, thought it interesting, looked around more, and found the &lt;a href=&quot;%7Bfilename%7D/releasing-software.md&quot;&gt;release rodeo&lt;/a&gt; post!&lt;/p&gt;
&lt;p&gt;He got rather upset. His issue was that I didn’t approach him directly. I think that’s fair, I feel I would do this under normal circumstances, however due to history,&lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; it was difficult for me to take that step. I did solve the underlying process problem to him. &lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; There may not even have been a need to single out specific roles in the original blog post, I could’ve chatted in more general terms and get the story across. I think in the future I won’t do that anymore. It’s just distracting to single out people (even anonymously). Because it wasn’t a post about venting, although I admit, there was a fair bit of venting. It was about identifying and solving the underlying issue, despite being frustrated! Reading it back now I don’t think I said anything wrong. Aside from using chatgpt to make it sound like it’s not me 😅&lt;/p&gt;
&lt;p&gt;Anyway this is the last post in this unexpected “series”. I learned that I should be careful with what I write, these pages are read by more people than I thought! Please leave a like, subscribe and share your job-rants in the comments below.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;I decided to leave due to unrelated reasons. It’s a good place to work, however I had some tax issues forcing me to quit.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;At some point the company had hired another manager whose only skill was office politics. Which caused me a lot of grief. This other manager brought the product manager from the original blog post on board and for some reason I had an association in my brain, perhaps unfairly.&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;Perhaps in a not too social way, but what do you expect from someone who obsesses over computers for most of their life!&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>BONUS Announcement mysql pure unfork</title>
    <link href="https://jappieklooster.nl/bonus-announcement-mysql-pure-unfork.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2023-08-14:/bonus-announcement-mysql-pure-unfork.html</id>
    <published>2023-08-14T17:37:00Z</published>
    <updated>2023-08-14T17:37:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;Good news! I’ve come to an agreement with the maintainer of &lt;a href=&quot;https://hackage.haskell.org/package/mysql-haskell&quot;&gt;mysql-haskell&lt;/a&gt;, &lt;a href=&quot;https://github.com/winterland1989&quot;&gt;winterland&lt;/a&gt;. I’ll become a co-maintainer.&lt;/p&gt;
&lt;p&gt;What this means in practice is that I’ll deprecate &lt;a href=&quot;https://hackage.haskell.org/package/mysql-pure&quot;&gt;mysql-pure&lt;/a&gt; and merge the changes back into &lt;a href=&quot;https://hackage.haskell.org/package/mysql-haskell&quot;&gt;mysql-haskell&lt;/a&gt;. This will make upgrades far more convenient for users. That’s you! It isn’t&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Good news! I’ve come to an agreement with the maintainer of &lt;a href=&quot;https://hackage.haskell.org/package/mysql-haskell&quot;&gt;mysql-haskell&lt;/a&gt;, &lt;a href=&quot;https://github.com/winterland1989&quot;&gt;winterland&lt;/a&gt;. I’ll become a co-maintainer.&lt;/p&gt;
&lt;p&gt;What this means in practice is that I’ll deprecate &lt;a href=&quot;https://hackage.haskell.org/package/mysql-pure&quot;&gt;mysql-pure&lt;/a&gt; and merge the changes back into &lt;a href=&quot;https://hackage.haskell.org/package/mysql-haskell&quot;&gt;mysql-haskell&lt;/a&gt;. This will make upgrades far more convenient for users. That’s you! It isn’t a big deal for me either way, as I simply want the project to build reliably. There’s no other agenda than that, so convenience for users is paramount. &lt;a href=&quot;https://hackage.haskell.org/package/persistent-mysql-pure&quot;&gt;persistent-mysql-pure&lt;/a&gt; will, from now on, depend on mysql-haskell again. This fork is still necessary for the persistent users out there, because my &lt;a href=&quot;https://discourse.haskell.org/t/ann-mysql-pure-fork-of-mysql-haskell/7297&quot;&gt;announcement&lt;/a&gt; and &lt;a href=&quot;https://github.com/naushadh/persistent-mysql-haskell/issues/2&quot;&gt;issue&lt;/a&gt; failed to reach that maintainer.&lt;/p&gt;
&lt;p&gt;When winterland becomes active again in the future, as they intend to, I hope to hand off maintainership back to them.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Announcing mysql pure fork</title>
    <link href="https://jappieklooster.nl/announcing-mysql-pure-fork.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2023-08-13:/announcing-mysql-pure-fork.html</id>
    <published>2023-08-13T13:37:00Z</published>
    <updated>2023-08-13T13:37:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;I’ve forked &lt;a href=&quot;https://hackage.haskell.org/package/mysql-haskell&quot;&gt;mysql-haskell&lt;/a&gt; and &lt;a href=&quot;https://hackage.haskell.org/package/persistent-mysql-haskell&quot;&gt;persistent-mysql-haskell&lt;/a&gt; into &lt;a href=&quot;https://hackage.haskell.org/package/mysql-pure&quot;&gt;mysql-pure&lt;/a&gt; and &lt;a href=&quot;https://hackage.haskell.org/package/persistent-mysql-pure&quot;&gt;persistent-mysql-pure&lt;/a&gt;. The original packages were no longer maintained and frequently caused me issues during GHC upgrades, so I decided to take over maintainership. For example, bounds were outdated, or I needed minor patches found on &lt;a href=&quot;https://github.com/chordify/persistent/tree/persistent-mysql-haskell-9.2&quot;&gt;obscure branches&lt;/a&gt; in &lt;a href=&quot;https://github.com/naushadh/word24/tree/ci&quot;&gt;unrelated repositories&lt;/a&gt;.&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;I’ve forked &lt;a href=&quot;https://hackage.haskell.org/package/mysql-haskell&quot;&gt;mysql-haskell&lt;/a&gt; and &lt;a href=&quot;https://hackage.haskell.org/package/persistent-mysql-haskell&quot;&gt;persistent-mysql-haskell&lt;/a&gt; into &lt;a href=&quot;https://hackage.haskell.org/package/mysql-pure&quot;&gt;mysql-pure&lt;/a&gt; and &lt;a href=&quot;https://hackage.haskell.org/package/persistent-mysql-pure&quot;&gt;persistent-mysql-pure&lt;/a&gt;. The original packages were no longer maintained and frequently caused me issues during GHC upgrades, so I decided to take over maintainership. For example, bounds were outdated, or I needed minor patches found on &lt;a href=&quot;https://github.com/chordify/persistent/tree/persistent-mysql-haskell-9.2&quot;&gt;obscure branches&lt;/a&gt; in &lt;a href=&quot;https://github.com/naushadh/word24/tree/ci&quot;&gt;unrelated repositories&lt;/a&gt;. I’ve set up various CI automations. Specifically, I’ve integrated automated version bumping from &lt;a href=&quot;https://github.com/nomeata/haskell-bounds-bump-action&quot;&gt;nomeata&lt;/a&gt; and incorporated &lt;a href=&quot;https://github.com/jappeace/haskell-nightly&quot;&gt;haskell nightly&lt;/a&gt; builds&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I forked because I didn’t want to go through the &lt;a href=&quot;https://wiki.haskell.org/Taking_over_a_package&quot;&gt;process&lt;/a&gt; of obtaining the Hackage namespace, which I found discouraging. Furthermore, mysql-pure merges several dependencies of mysql-haskell into one package. &lt;a href=&quot;https://hackage.haskell.org/package/word24&quot;&gt;word24&lt;/a&gt;, &lt;a href=&quot;https://hackage.haskell.org/package/binary-parsers&quot;&gt;binary-parsers&lt;/a&gt;, and &lt;a href=&quot;https://hackage.haskell.org/package/wire-streams&quot;&gt;wirestreams&lt;/a&gt; are all now part of this one package. This presents a somewhat different perspective on package organization, which might warrant a new package &lt;em&gt;anyway&lt;/em&gt;. However, practically no third-party packages depend on the packages I merged, So having them separated results in more work nobody appears to benefit from.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;This instantly found an issue in GHC on Windows for the linker: https://gitlab.haskell.org/ghc/ghc/-/issues/23835.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Follow up release rodeo</title>
    <link href="https://jappieklooster.nl/follow-up-release-rodeo.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2023-07-17:/follow-up-release-rodeo.html</id>
    <published>2023-07-17T00:00:00Z</published>
    <updated>2023-07-17T00:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;p&gt;This is a follow-up on the &lt;a href=&quot;%7Bfilename%7D/releasing-software.md&quot;&gt;release rodeo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After I wrote that blog post, the CTO found it quickly by coincidence. He was quite okay with everything I had written. However, he took issue with that I called his critique “scolding”. I suppose he didn’t exactly scold me. I&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;This is a follow-up on the &lt;a href=&quot;%7Bfilename%7D/releasing-software.md&quot;&gt;release rodeo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After I wrote that blog post, the CTO found it quickly by coincidence. He was quite okay with everything I had written. However, he took issue with that I called his critique “scolding”. I suppose he didn’t exactly scold me. I described it that way because it aligns with my personality: I’m an honest person, I have high standards, and I take criticism extremely seriously. Even when someone says, “You’re kind of doing this badly sometimes,” I interpret it as “You suck, Jappie, you need to do better”.&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; This doesn’t mean I’m unkind to others, however I put myself to high standards. He also warned me that if the PM were ever to stumble upon this post, they might get quite upset. I am aware of this possibility, which is why I didn’t advertise this article at all. It seems rather unlikely to me he’d go read a tech blog anyway. The point wasn’t to create more conflict, but instead to analyze the situation and prevent it. &lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A few days later, another engineer found themselves tangled in the release flag situation. At this point, I realized it was crucial to inform everyone about how these release flags should work. Therefore, I set out to describe the current situation and propose some recommendations. After outlining the recommendations, I realized the points of contention weren’t numerous. The process worked in principle (aside from some peculiar naming conventions), and I believe that most of the involved parties were simply uninformed. I created a GitHub RFC&lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; and tagged the relevant parties on it. This enticed them to read it and become informed and give comments if necessary. As an open discussion, this also helped get clarification on points I had missed. Since then, we’ve had no more release issues. It appears that writing down the process and informing everyone resolved the issue.&lt;/p&gt;
&lt;p&gt;A lesson learned from this experience is that anger can be rather productive. If there’s something you can do about the situation, it’s productive to think about why you’re angry and devise a plan of action. In this case, I indeed solved a rather annoying but important issue by taking a relatively simple action. Anyone could’ve done this.&lt;/p&gt;
&lt;p&gt;Note that this post has a &lt;a href=&quot;%7Bfilename%7D/followup-followup-releasing-software.md&quot;&gt;follow up&lt;/a&gt;.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;From this, we can also derive the reason for my bluntness when angry. For a mind that is harsh on itself by default, being nice requires extra effort.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;And also a little bit of venting!&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;Request for change, eg an invitation to discuss a change in process or system.&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>MySQL Persistent Support for Haskell on Windows</title>
    <link href="https://jappieklooster.nl/mysql-persistent-support-for-haskell-on-windows.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2023-07-01:/mysql-persistent-support-for-haskell-on-windows.html</id>
    <published>2023-07-01T15:44:00Z</published>
    <updated>2023-08-13T14:09:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;Using Haskell on Windows can be very useful in a &lt;a href=&quot;https://www.wampserver.com/en/&quot;&gt;WAMP&lt;/a&gt; like situation, where the main legacy codebase is stuck at PHP 5.6&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; . However, any new pages can be written with Haskell, which is much easier to upgrade since the compiler will inform you about most changes. New&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Using Haskell on Windows can be very useful in a &lt;a href=&quot;https://www.wampserver.com/en/&quot;&gt;WAMP&lt;/a&gt; like situation, where the main legacy codebase is stuck at PHP 5.6&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; . However, any new pages can be written with Haskell, which is much easier to upgrade since the compiler will inform you about most changes. New pages can, for example, be written in &lt;a href=&quot;https://www.yesodweb.com/&quot;&gt;Yesod&lt;/a&gt;, and then simply linked to, or posted to with normal HTML/HTTP. The database can be used as an API to interact with PHP state. Although I’ve not set up a full Yesod web server on Windows (yet), these steps include the hardest part, the database connection. Feel free to &lt;a href=&quot;mailto:hi@jappie.me&quot;&gt;contact me&lt;/a&gt; if you want help with that.&lt;/p&gt;
&lt;p&gt;This is a small instructional blog post, primarily for my own reference, on how to get MySQL support for programs on Windows. These steps are for &lt;em&gt;native&lt;/em&gt; Windows support. There’s no WSL involvement. Specifically, we are obtaining MySQL-persistent support with the help of the pure Haskell &lt;a href=&quot;https://hackage.haskell.org/package/persistent-mysql-haskell&quot;&gt;MySQL bindings&lt;/a&gt;. Because the bindings are in pure Haskell, they’re easily portable. Haskell abstracts most operating system oddities away.&lt;/p&gt;
&lt;p&gt;There is support for cross-compilation on Windows somewhere available &lt;a href=&quot;https://github.com/input-output-hk/nix-hs-hello-windows&quot;&gt;here&lt;/a&gt;. However, at the time of writing, it has not been implemented in &lt;a href=&quot;https://github.com/NixOS/nixpkgs/issues/36200&quot;&gt;mainstream nixpkgs&lt;/a&gt;. Therefore, future Jappie, it would be better to abandon your Nix aspirations and follow these steps.&lt;/p&gt;
&lt;h1 id=&quot;install-ghcup&quot;&gt;Install ghcup&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.haskell.org/cabal/&quot;&gt;Cabal&lt;/a&gt; is a package manager for Haskell only. It assumes that native bindings exist. We’ll provide these using &lt;a href=&quot;https://www.msys2.org/&quot;&gt;msys2&lt;/a&gt;, which offers a shell and system isolation. On top of that, we utilize &lt;a href=&quot;https://wiki.archlinux.org/title/pacman&quot;&gt;pacman&lt;/a&gt;. With this combination, we can create a Linux-like environment to generate &lt;em&gt;native&lt;/em&gt; Windows executables! We use ghcup to manage the versions of these programs. The name comes from ghc, the main compiler. this is also installed. &lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Follow the instructions in the install link: &lt;a href=&quot;https://www.haskell.org/ghcup/#ghcup-instructions-win&quot;&gt;https://www.haskell.org/ghcup/#ghcup-instructions-win&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Earlier versions suggested using &lt;a href=&quot;https://chocolatey.org/&quot;&gt;Chocolatey&lt;/a&gt;, but don’t use Chocolatey. It is akin to &lt;a href=&quot;https://manpages.ubuntu.com/manpages/xenial/man8/apt.8.html&quot;&gt;apt&lt;/a&gt; and can cause significant problems with Haskell packages. If you need system package management and Haskell package management, use &lt;a href=&quot;https://nixos.org/&quot;&gt;Nix&lt;/a&gt;. It’s the only package manager that seems to work reliably. However nix has no native Windows support.&lt;/p&gt;
&lt;p&gt;Answer the other questions:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;   default path &amp;quot;C:\&amp;quot; -- 1
   cabal to C:\cabal -- 2
   HLS N -- 3
   stack N -- 4
   msys2 Y -- 5&lt;/code&gt;&lt;/pre&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;The path used for ghcup isn’t important.&lt;/li&gt;
&lt;li&gt;Again, it doesn’t matter. Placing everything at the top-level C makes it easy to find.&lt;/li&gt;
&lt;li&gt;I don’t use Windows for editing. I mounted the project folder as a virtual box folder. On Linux, I use Emacs to maintain changes, and I run the Windows based cabal command in this mounted folder.&lt;/li&gt;
&lt;li&gt;We don’t use stack as it adds another layer of complexity on top of Cabal.&lt;/li&gt;
&lt;li&gt;This is necessary to build the required system dependencies with relative ease.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Keep in mind that you need to reopen the terminal for the new programs, such as &lt;code&gt;cabal&lt;/code&gt; and &lt;code&gt;ghcup&lt;/code&gt;, to register on the &lt;code&gt;$PATH&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&quot;build-manually-with-msys2&quot;&gt;Build manually with msys2&lt;/h1&gt;
&lt;p&gt;Next, you need to open an msys2 terminal (which is different from a PowerShell). To install git, use pacman in a mingw64 terminal, which can be found in &lt;code&gt;C:\ghcup\msys64&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pacman -S git&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&lt;/p&gt;
&lt;p&gt;are two spells, and I’m not sure which one made it work:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cabal user-config -a &amp;quot;extra-prog-path: %HOME%\.ghcup\bin, %HOME%\AppData\Roaming\cabal\bin, C:\\ghcup\msys64, C:\\ghcup\msys64\mingw64\bin, C:\\ghcup\msys64\user\bin&amp;quot; -a &amp;quot;extra-include-dirs: C:\\ghcup\msys64\mingw64\include&amp;quot; -a &amp;quot;extra-lib-dirs: C:\\ghcup\msys64\mingw64\lib&amp;quot; -f init&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also did this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    $Env:Path += &amp;quot;;C:\ghcup\msys64\mingw64\bin&amp;quot;
    $Env:Path += &amp;quot;;C:\ghcup\msys64\usr\bin&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After these steps, it worked. Now cabal can find git, and therefore download our patched versions. Fret not, I’m working on getting these changes into Hackage directly. It just takes time to do all the politics involved and give people the opportunity to reply to my requests. However, even if I manage to get the changes upstream, there is a big chance you’d need one native dependency or another anyway, which this setup will give you.&lt;/p&gt;
&lt;h1 id=&quot;cabal&quot;&gt;Cabal&lt;/h1&gt;
&lt;p&gt;You can generate an intial configuration with &lt;code&gt;cabal init&lt;/code&gt;, then add &lt;code&gt;persistent-mysql-haskell&lt;/code&gt; dependency to your build-depends: &lt;code&gt;packagename.cabal&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  build-depends:
    , base                      &amp;gt;=4.9.1.0 &amp;amp;&amp;amp; &amp;lt;5
    , persistent-mysql-pure&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In combination with the &lt;code&gt;cabal.project&lt;/code&gt; file, cabal should be using git instead of hackage to find that package. Test it out with with &lt;code&gt;cabal build&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;This should set you up with Windows development for Haskell in more complicated setups than just some puzzles. You’re probably better off getting an Ubuntu VM if you just want to build something &lt;em&gt;new&lt;/em&gt; in Haskell. However, for legacy integrations, this will work. If not, please leave a comment below, or &lt;a href=&quot;mailto:hi@jappie.me&quot;&gt;contact me&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;update-cabal-edit&quot;&gt;Update: Cabal edit&lt;/h1&gt;
&lt;p&gt;The cabal section used to contain below text, however since I’ve forked &lt;a href=&quot;%7Bfilename%7D/mysql-pure.md&quot;&gt;mysql-pure&lt;/a&gt;. this is no longer necessary.&lt;/p&gt;
&lt;p&gt;You need to instruct Cabal to use the correct MySQL packages &lt;code&gt;project.cabal&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;cabal&quot;&gt;&lt;code&gt;packages: .

allow-newer: wire-streams:bytestring, binary-parsers:bytestring

source-repository-package
    type: git
    location: https://github.com/chordify/persistent
    tag: cf735587e590369e62168dacc2c3c2411493ae6d
    subdir: persistent-mysql-haskell

source-repository-package
    type:git
    location: https://github.com/jappeace/mysql-haskell
    tag: 8f95f0a4749b888eba96173378acbede3955ab60

source-repository-package
    type:git
    location: https://github.com/naushadh/word24
    tag: 1cc234d53923c270e888fdeac868c34306c43c70

source-repository-package
    type:git
    location: https://github.com/naushadh/word24
    tag: 1cc234d53923c270e888fdeac868c34306c43c70&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can generate an intial configuration with &lt;code&gt;cabal init&lt;/code&gt;, then add &lt;code&gt;persistent-mysql-haskell&lt;/code&gt; dependency to your build-depends: &lt;code&gt;packagename.cabal&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  build-depends:
    , base                      &amp;gt;=4.9.1.0 &amp;amp;&amp;amp; &amp;lt;5
    , persistent-mysql-haskell&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In combination with the &lt;code&gt;cabal.project&lt;/code&gt; file, cabal should be using git instead of hackage to find that package. Test it out with with &lt;code&gt;cabal build&lt;/code&gt;.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;Forever, because upgrading is too painful and introduces to many runtime bugs.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;To be clear, the major difference with nix is that nix in principle leverages cabal and ghc, but nix manages the versions of these, but also solves the native part in a reproducible manner. This means I can write a script for a build and it mostly will keep on working forever, unless source mirrors disappear for example.&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>The Release Rodeo</title>
    <link href="https://jappieklooster.nl/the-release-rodeo.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2023-05-31:/the-release-rodeo.html</id>
    <published>2023-05-31T20:14:00Z</published>
    <updated>2023-08-19T12:38:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;style&gt;
img[src=&quot;/images/2023/release-rodeo.png&quot;]{
  height: 20em;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2023/release-rodeo.png&quot; alt=&quot;Release rodeo~&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Release rodeo~&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In the beginning, there was nothing. We merged completed features after a month or so of development, leading to large PRs and often unexpected implementations. Then, feature flags were introduced. This allowed the merging of code in chunks, enabling QA to test thoroughly. The&lt;/p&gt;</summary>
    <content type="html">&lt;style&gt;
img[src=&quot;/images/2023/release-rodeo.png&quot;]{
  height: 20em;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2023/release-rodeo.png&quot; alt=&quot;Release rodeo~&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Release rodeo~&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In the beginning, there was nothing. We merged completed features after a month or so of development, leading to large PRs and often unexpected implementations. Then, feature flags were introduced. This allowed the merging of code in chunks, enabling QA to test thoroughly. The people in charge could now also decide &lt;em&gt;when&lt;/em&gt; to release. Because this also facilitated more, smaller PRs&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;, it also made the reviewing process much easier. Everything was awesome in paradise, but not all was as it seemed…&lt;/p&gt;
&lt;p&gt;The flag count grew, and salespeople started to realize they could enable flags for certain customers. This went well, in the beginning. Except that these features were still in development. So, on one occasion, a client success person panicked, after a fancy file uploader behind a feature flag disappeared. This happened because it was merged into another feature flag&lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;. Now certain customers no longer had access to the file uploader to which they had grown accustomed, breaking their entire workflow.&lt;/p&gt;
&lt;p&gt;Note that in this setting, a customer is a large corporation with thousands of employees. So if one of them becomes unhappy, the startup could lose a lot. Not just money but also reputation, which translates into future sales, potentially threatening the survival of the startup. Up until now, this hasn’t happened; all customers who’ve signed up have always been kept happy.&lt;/p&gt;
&lt;p&gt;Anyway, long story short, since the feature was being used in production, I strongly urged its release. This was discussed internally, and everyone agreed on releasing this file uploader feature. &lt;em&gt;Everyone&lt;/em&gt;. However, some requests were made, for example, there were redundant form elements. The manager suggested also deleting the old file uploading button. This was a good idea, because with this change the old flow would be quite broken; we had already removed error messages. The manager in charge was tagged and ignored the PR for several days, after which we decided to merge. We had already decided to release this feature, so his approval wasn’t necessary according to our customs.&lt;/p&gt;
&lt;p&gt;Fast forward to the next week, and our dear client success person was once again in a panic. It turns out that one of our older customers was still using that confusing button. So we had to put it back. I warned them that this old flow was broken, lacked a lot of elements and would cause confusion. They just wanted it back however, so I complied. This was a rather minor change, however the manager in charge of releases, did what any good leader would do and blamed the developers. &lt;em&gt;Even though this was his own suggestion&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I wouldn’t be writing an angry blogpost if it was the only incident. There is more. He was right about the confusion that followed from leaving the button. QA got confused, another dev got confused, I’m surprised more customers weren’t complaining about this. Although they likely just ended up feeling stupid and didn’t complain, which is &lt;em&gt;worse&lt;/em&gt;. It seems impossible to delete that darn button, however.&lt;/p&gt;
&lt;p&gt;Moving forward a month, a large client was preparing for a demo. I started working on a “detection” feature which we needed to impress said client. We had a meeting to figure out what we could get done before the demo. From this we learned we had to modify the Elm apps. These Elm apps represent HTML tables that open up a modal with the specific data comprising those tables. It’s like eight different tables, all looking slightly different, all piped into the same Elm app with flags specifying how it should look. We’ve had production bugs with these apps. They just stop functioning and you’ve no idea why. Furthermore, one of the best features of Elm, its debugger, is unusable because they overlap, since there are several Elm apps displayed on the page. As you can tell, I’m not too happy having to modify these. It’s a lot of pointless complexity.&lt;/p&gt;
&lt;p&gt;Anyway, the demo went well, as they skirted around those Elm apps and didn’t open the modals, which show the wrong information our new feature detects. Now, 2 weeks later, the manager decides it’s a good idea to release this feature. I learned this through an announcement in #general. But I wasn’t finished yet, since I was away for 1 week on vacation. I’m kind of shocked. If clients see those numbers don’t align with that new “detection” feature and our Elm apps, they’re going to freak out. Because they’re going to think our platform messed up their data somehow. So I reply to his announcement, because I know he’s well aware of this.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I’m not sure if I’d release the “feature” because “our Elm tables” are kind of incoherent right now. But if you’re happy with it 🤷‍♂️&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here I redacted the names of the specific features, replacing them by “feature” and “our Elm tables”. Now, is this blunt? Yes, but there is &lt;em&gt;a lot of money on the line&lt;/em&gt;. The same manager who blamed the developers for the missing button incident was also responsible for this release. Naturally, he employed his remarkable management skills and decided to throw a tantrum, persuading the CTO to scold me. Indeed, I was reprimanded and praised simultaneously. It was beneficial that we detected this issue early, but I was told that my communication was too blunt and insufficiently precise. I believe there’s truth in this. I could’ve been calmer, but maintaining composure is challenging in a stressful situation. Part of this blog post is about circumventing such situations in the future. The manager could’ve performed better too. For instance, he could’ve inquired in #tech before releasing, “Are there any serious issues remaining with feature X, Y, or Z?” Just like one would do in a team. Alternatively, he could’ve engaged with my response in #general to figure out what was happening.&lt;/p&gt;
&lt;p&gt;I was angry when starting to write this. And while I wanted to blame a particular individual, I won’t. This is the wrong mindset. &lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; Rather than blaming specific individuals, I prefer to think in terms of systems. How is our process so broken and causing stress? Well, no one has cared about thinking about how all of this should work internally, at least. This is so bad we don’t even have a proper definition of what it means to release a feature:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;We delete the feature flag and old code.&lt;/li&gt;
&lt;li&gt;We enable the feature flag for all customers as a setting.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Point &lt;code&gt;1.&lt;/code&gt; should happen eventually, but after reading the external communication process, I think we should first do &lt;code&gt;2.&lt;/code&gt;, wait for some time, and then delete the feature flag. It’d be nice if we put a limit on that as well, so developers can safely delete at some point. Even though there appears to be documentation on what clients need to be informed, internally we have no clue who to tell what or get involved. We don’t have a grace period either, allowing people to comment on a release. For example, the customer success people can just say if a button is missing in this grace period, or a developer implementing it can just say that hey, we’re showing incoherent stuff. There is no guidance on how big a release should be, are smaller ones better or bigger ones. It seems like the customer success and marketing people prefer big releases. So they can use it as a marketing moment, and have an easier time demoing more features in one go. But I suspect for engineers, smaller ones are preferred, as this allows them not to be overwhelmed if issues arise.&lt;/p&gt;
&lt;p&gt;How would you release? I’ve always learned to release early and release often. But ever since the introduction of feature flags, we’ve just not been releasing, until it became a problem. In typical startup style sledgehammer fashion, the problem was solved; release a bunch of stuff, and for the unfinished parts we peeled them off, putting them behind different flags. But does the path towards releasing this software have to be so stressful? I feel we’re doing it wrong. The lack of some kind of formalized strategy causes some issues here, I think. We’re just doing stuff, inconsistently, and coordination revolves around people being shocked and in a panic. This clearly isn’t working.&lt;/p&gt;
&lt;p&gt;Documenting what I believe should happen, without naming specific individuals or organizations, &lt;a href=&quot;#fn4&quot; class=&quot;footnote-ref&quot; id=&quot;fnref4&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; has at least alleviated my anger. I’m not sure if the procedures I’ve outlined constitute a good process, hence I welcome comments, but I believe it’s a step forward from doing things haphazardly. Getting a timeline for a release at the very least would be beneficial. Therefore, with my anger tempered and a sense of progress, I deem this a successful blog post 💪. Please share your thoughts in the comments.&lt;/p&gt;
&lt;p&gt;Note that this post has a &lt;a href=&quot;%7Bfilename%7D/followup-releasing.md&quot;&gt;follow up&lt;/a&gt;.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;Pull requests, the primary mechanism in which developers align their changes. It opens up a moment for questions or comments.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;This itself was also problematic. The issue was that designers began wanting to make changes (as is their job), but developers started asking questions about how to implement these changes, and realized it was easier to just merge features.&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;Growing deaf to dharma and being trapped in samsara.&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;Could be anyone really, since I do work freelance :)&lt;a href=&quot;#fnref4&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>About my startup: raster.click</title>
    <link href="https://jappieklooster.nl/about-my-startup-rasterclick.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2023-02-25:/about-my-startup-rasterclick.html</id>
    <published>2023-02-25T20:40:00Z</published>
    <updated>2023-02-25T20:40:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;style&gt;
img[alt=&quot;raster logo&quot;]{
  width:40%;
  margin-left: 30%;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;img src=&quot;./images/2023/raster-logo.svg&quot; alt=&quot;raster logo&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;raster logo&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;As a founder of &lt;a href=&quot;https://raster.click/&quot;&gt;raster.click&lt;/a&gt;, I was passionate about providing rostering systems for restaurants that were easy to use and affordable. I worked hard to build a functional product that our users loved, and I was proud to have three paying&lt;/p&gt;</summary>
    <content type="html">&lt;style&gt;
img[alt=&quot;raster logo&quot;]{
  width:40%;
  margin-left: 30%;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;img src=&quot;./images/2023/raster-logo.svg&quot; alt=&quot;raster logo&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;raster logo&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;As a founder of &lt;a href=&quot;https://raster.click/&quot;&gt;raster.click&lt;/a&gt;, I was passionate about providing rostering systems for restaurants that were easy to use and affordable. I worked hard to build a functional product that our users loved, and I was proud to have three paying customers (eg restaurants) and around 90 active users (employees).&lt;/p&gt;
&lt;p&gt;Despite initial success, I realized that growth was not fast enough to become economically viable. I was unable to attract enough paying customers to cover costs. As a self-bootstrapped startup, I did not have access to significant funding, which made it challenging to scale the company and invest in marketing efforts. I also struggled with balancing time between product development and customer acquisition, which slowed growth even further.&lt;/p&gt;
&lt;p&gt;In 2019, I put in a lot of effort and remained dedicated to Raster.click. However, I eventually had to make the tough decision to discontinue my work and return to contract work. It was a heartbreaking decision, as I knew my product was loved by my users. They continued to use it until the COVID-19 pandemic hit and practically all usage stopped. The restaurant industry was severely affected by the pandemic, rendering rostering completely useless during that period.&lt;/p&gt;
&lt;p&gt;Although I still have an appreciation for the tech stack I chose - reflex + servant + beam - I’ve come to realize that a cool tech stack alone doesn’t matter to users. While it may result in faster product development, it ultimately doesn’t help if I can’t gather user requirements or attract new users. In hindsight, I could have been more productive by using yesod and relying on browser defaults instead of creating a single page app. However, the decision to end my startup was not based on the tech stack. Despite rolling out new features, I simply wasn’t gaining enough customers to make it a viable business.&lt;/p&gt;
&lt;p&gt;While I am proud of what I accomplished with Raster.click, I learned valuable lessons about the challenges of building and growing a startup without significant funding. Such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The importance of having a clear and viable business model: It’s essential to have a solid plan for how your startup will generate revenue and grow sustainably.&lt;/li&gt;
&lt;li&gt;The need for effective marketing and customer acquisition: Even if you have a great product, you need to be able to effectively reach and convince potential customers to use it.&lt;/li&gt;
&lt;li&gt;The importance of balancing product development and customer acquisition: While it’s important to create a great product, you also need to be able to attract and retain customers.&lt;/li&gt;
&lt;li&gt;The value of having access to funding: Without significant funding, it can be challenging to scale your startup and compete effectively in the market. Not to mention the stress caused by seeing your life savings slowly drop to zero.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I will take these lessons with me as I move forward with future endeavors.&lt;/p&gt;
&lt;p&gt;Although I stopped working on this project, it’s still &lt;a href=&quot;https://raster.click/&quot;&gt;operational&lt;/a&gt;. It costs very little money for me to keep this operational. That’s because it runs next to this site, &lt;a href=&quot;https://videocut.org/&quot;&gt;videocut&lt;/a&gt;, and &lt;a href=&quot;https://massapp.org/&quot;&gt;massapp&lt;/a&gt; on the &lt;a href=&quot;https://jappie.me/the-nix-mutli-monolith-machine-nmmm.html&quot;&gt;nmm approach&lt;/a&gt;. Yes, it’s sad I stopped working on this project, but if anyone is interested in using it, &lt;a href=&quot;https://raster.click/&quot;&gt;it’s right there&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Restoring msyql backup system on windows.</title>
    <link href="https://jappieklooster.nl/restoring-msyql-backup-system-on-windows.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2023-01-17:/restoring-msyql-backup-system-on-windows.html</id>
    <published>2023-01-17T17:00:00Z</published>
    <updated>2023-01-17T17:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;This is a quick after action report on restoring backups. This is mostly for future me to know what I did.&lt;/p&gt;
&lt;p&gt;The backup scripts on the main server stopped working. The IT person at that company had already figured out this was because of the database not booting on the&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;This is a quick after action report on restoring backups. This is mostly for future me to know what I did.&lt;/p&gt;
&lt;p&gt;The backup scripts on the main server stopped working. The IT person at that company had already figured out this was because of the database not booting on the machines which were supposed to receive the backups, but figuring out the underlying cause was beyond his capability. So I was called in. Yes. I’m slowly turning into a database administrator at &lt;a href=&quot;https://jappie.me/restoring-mysql-innodb-on-windows.html&quot;&gt;this&lt;/a&gt; &lt;a href=&quot;https://jappie.me/the-peculiar-event-sourced-deadlock.html&quot;&gt;rate&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So xampp&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; told us to look at the logs, those said:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;error: trying to access page number 123 in space 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Stack overflow &lt;a href=&quot;https://stackoverflow.com/questions/38245974/mysql-server-crashes-innodb-outside-the-tablespace-bounds&quot;&gt;said&lt;/a&gt; that we need to recover from backup if &lt;code&gt;innodb_force_recovery&lt;/code&gt; doesn’t work. It doesn’t say how. Remember, we can’t even start the database! What I did instead was deleting the &lt;code&gt;innodb0&lt;/code&gt; file, and the &lt;code&gt;innodb.log&lt;/code&gt; files. Remember, I actually don’t care about the data, it’s just a backup machine. This made the database boot again, making it ready to receive backups.&lt;/p&gt;
&lt;p&gt;One more peculiarity occurred (of course). The script would timeout saying it’s a connection error. However this error happened every time I executed the script, and I’d assume that at an office the connection is pretty reliable. This made me think it was just mislabeling the error. Once again &lt;a href=&quot;https://stackoverflow.com/a/24555191&quot;&gt;stack overflow&lt;/a&gt; agreed. This database has lots of blob data, so setting &lt;code&gt;max_allowed_packet&lt;/code&gt; to &lt;code&gt;64M&lt;/code&gt; indeed fixed the connection error.&lt;/p&gt;
&lt;p&gt;I’m starting to think I should move this entire stack over to postgres, at least that doesn’t randomly start failing, or has mislabeled errors. But I know that’s next to impossible with this clients’ resources. So for now, Jappie is here for all your database concerns.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;Why are they using xampp? Legacy choices. Remember I don’t get to chose their tech stack, that has been decided more then a decade ago. I’m just keeping it operational.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>The peculiar event sourced deadlock</title>
    <link href="https://jappieklooster.nl/the-peculiar-event-sourced-deadlock.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2023-01-15:/the-peculiar-event-sourced-deadlock.html</id>
    <published>2023-01-15T22:30:00Z</published>
    <updated>2023-01-15T22:30:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;figure&gt;
&lt;img src=&quot;images/2023/postgresql-deadlock.png&quot; alt=&quot;THE UNDEAD LOCK OF DETH&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;THE UNDEAD LOCK OF DETH&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;One thing that always surprises me is how casually serious problems are phrased by business people in their blissful ignorance. “Hey why am I seeing the down for maintenance screen?” “Oh try it now, the pack uploading has finished”, Said the QA engineer to the&lt;/p&gt;</summary>
    <content type="html">&lt;figure&gt;
&lt;img src=&quot;images/2023/postgresql-deadlock.png&quot; alt=&quot;THE UNDEAD LOCK OF DETH&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;THE UNDEAD LOCK OF DETH&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;One thing that always surprises me is how casually serious problems are phrased by business people in their blissful ignorance. “Hey why am I seeing the down for maintenance screen?” “Oh try it now, the pack uploading has finished”, Said the QA engineer to the product manager. Once I saw this on slack, I grew really suspicious and started asking questions. After all, isn’t it a bit odd we’re seeing a down for maintenance screen in one part of the system, simply because another part is being used?&lt;/p&gt;
&lt;p&gt;Initially we thought this was caused by high CPU usage. The graphs showed high CPU load while processing packs, so maybe the rest of the system was being deprioritized somehow. Before assuming that was the cause however, I decided to reproduce the issue first. Here I noticed I could for example load the risk index easily (a read operation), but connecting a risk to a pack (a write operation), would hang forever. This made me suspect that the issue wasn’t CPU usage at all, so I asked Postgres to list &lt;a href=&quot;https://wiki.postgresql.org/wiki/Lock_Monitoring&quot;&gt;it’s locks&lt;/a&gt;. Which showed several locks in progress. This lead me to the event source system. The event source system is at the core of all our business logic. In essence, it provides a ledger of all important business write activities that can happen. &lt;a href=&quot;https://www.youtube.com/watch?v=8JKjvY4etTY&quot;&gt;This is useful&lt;/a&gt; for auditing purposes for example.&lt;/p&gt;
&lt;p&gt;Welcome to an after action report of a complicated system level bug. It took me a week to find a satisfying solution. To start I need to sketch context. I’ll only use raw SQL because this entire story is related to the database and how we use it for event sourcing. So consider the tables of an event source system:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode sql&quot;&gt;&lt;code class=&quot;sourceCode sql&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;TABLE&lt;/span&gt; event (&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt; serial &lt;span class=&quot;kw&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    payload jsonb &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;character&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;varying&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;#cb1-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    created &lt;span class=&quot;dt&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;zone&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;#cb1-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;);&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;#cb1-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;#cb1-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;TABLE&lt;/span&gt; event_last_applied (&lt;/span&gt;
&lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;#cb1-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt; serial &lt;span class=&quot;kw&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb1-10&quot;&gt;&lt;a href=&quot;#cb1-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    event_id bigint &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;REFERENCES&lt;/span&gt; event (&lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb1-11&quot;&gt;&lt;a href=&quot;#cb1-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In here the &lt;code&gt;type&lt;/code&gt; and &lt;code&gt;payload&lt;/code&gt; fields contains the information to (re)apply that event. The &lt;code&gt;type&lt;/code&gt; will indicate what business logic or queries to execute, and the &lt;code&gt;payload&lt;/code&gt; holds information for that logic. As we’ll see later, these queries will involve modifying other normal tables within a transaction. This application of events, or re-application through business logic or queries is called projecting. A &lt;code&gt;type&lt;/code&gt; can for example be &lt;code&gt;create-user&lt;/code&gt; and the &lt;code&gt;payload&lt;/code&gt; would contain the data required for creating said user, for example &lt;code&gt;{email:&apos;hi@jappie.me&apos;}&lt;/code&gt;. The &lt;code&gt;id&lt;/code&gt; provides a unique global ordering, and the &lt;code&gt;created&lt;/code&gt; field contains a timestamp of when the event was created, which is used for database administration purposes. Finally, the &lt;code&gt;event_last_applied&lt;/code&gt; table is used to indicate whichever event was last applied, so the system can figure out if additional events need to be re-projected from the &lt;code&gt;event&lt;/code&gt; table.&lt;/p&gt;
&lt;p&gt;Inserting an event works by projecting an event to normal Postgres tables in a transaction. Once this operation is not rejected by foreign keys, type errors or program exceptions, the event gets recorded in the ledger, also known as the &lt;code&gt;event&lt;/code&gt; table. For example:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode sql&quot;&gt;&lt;code class=&quot;sourceCode sql&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;cf&quot;&gt;begin&lt;/span&gt;;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;#cb2-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;/* left out projection code, insert user into tables here,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;#cb2-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;or do other projection stuff, as dictated by the event type*/&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;#cb2-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;#cb2-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;INTO&lt;/span&gt; event (payload, &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt;, created)&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;#cb2-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;VALUES&lt;/span&gt; (&lt;span class=&quot;st&quot;&gt;&amp;#39;{&amp;quot;email&amp;quot;:&amp;quot;hi@jappie.me&amp;quot;}&amp;#39;&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&amp;#39;create-user&amp;#39;&lt;/span&gt;, now());&lt;/span&gt;
&lt;span id=&quot;cb2-8&quot;&gt;&lt;a href=&quot;#cb2-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;INTO&lt;/span&gt; event_last_applied (&lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt;, event_id)&lt;/span&gt;
&lt;span id=&quot;cb2-9&quot;&gt;&lt;a href=&quot;#cb2-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;fu&quot;&gt;max&lt;/span&gt;(&lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;FROM&lt;/span&gt; event&lt;/span&gt;
&lt;span id=&quot;cb2-10&quot;&gt;&lt;a href=&quot;#cb2-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;ON&lt;/span&gt; CONFLICT (&lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb2-11&quot;&gt;&lt;a href=&quot;#cb2-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    DO &lt;span class=&quot;kw&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;SET&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-12&quot;&gt;&lt;a href=&quot;#cb2-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        event_id &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; lastval();&lt;/span&gt;
&lt;span id=&quot;cb2-13&quot;&gt;&lt;a href=&quot;#cb2-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;commit&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If the projection fails the entire event gets rejected, which means all changes within the transaction get rolled back by Postgres. This applies relational guarantees, to a non-relational system trough a transaction. We also weave this transaction trough business logic code, so that in case of an exception, we rollback. Quite an elegant solution, which &lt;a href=&quot;https://garba.org/posts/2016/event-sourcing/#materialised-view-pattern&quot;&gt;I did&lt;/a&gt; &lt;a href=&quot;https://www.ahri.net/2019/07/practical-event-driven-and-sourced-programs-in-haskell/&quot;&gt;not invent&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On system boot we figure out if we need to reproject or not, the query is rather simple:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode sql&quot;&gt;&lt;code class=&quot;sourceCode sql&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt;, payload &lt;span class=&quot;kw&quot;&gt;FROM&lt;/span&gt; event&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;#cb3-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;WHERE&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;#cb3-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; (&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;#cb3-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;SELECT&lt;/span&gt; event_id &lt;span class=&quot;kw&quot;&gt;FROM&lt;/span&gt; event_last_applied&lt;/span&gt;
&lt;span id=&quot;cb3-5&quot;&gt;&lt;a href=&quot;#cb3-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb3-6&quot;&gt;&lt;a href=&quot;#cb3-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;BY&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-7&quot;&gt;&lt;a href=&quot;#cb3-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;ASC&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which returns something like this, telling the system what to do:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    type     |          payload          
-------------+---------------------------
 create-user | {&amp;quot;email&amp;quot;: &amp;quot;hi@jappie.me&amp;quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that, we can reproject, also known as replaying history. Replaying history involves truncating all tables that are event sourced. And then truncating the &lt;code&gt;event_last_applied&lt;/code&gt; table, which in this case just removes the one row. Then the system will notice it needs to replay events on boot for example. This is a rather dangerous operation, because if any event fails, you may have potentially lost data. A lot of things can go wrong with a large history, foreign keys, exceptions, serialization mismatches, events out of order etc. Transactions can help here as well, and make this re-projection safe.&lt;/p&gt;
&lt;h2 id=&quot;deadlock&quot;&gt;Deadlock&lt;/h2&gt;
&lt;p&gt;There is one more important piece of context: An event maybe composed with other events into larger transactions. For example, if we create a user, we may also assign him to a company within the same transaction. In SQL that looks like this:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode sql&quot;&gt;&lt;code class=&quot;sourceCode sql&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;cf&quot;&gt;BEGIN&lt;/span&gt;;&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;#cb5-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-3&quot;&gt;&lt;a href=&quot;#cb5-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;/* left out projection code, insert user into tables here */&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-4&quot;&gt;&lt;a href=&quot;#cb5-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-5&quot;&gt;&lt;a href=&quot;#cb5-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;INTO&lt;/span&gt; event (payload, &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt;, created)&lt;/span&gt;
&lt;span id=&quot;cb5-6&quot;&gt;&lt;a href=&quot;#cb5-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;VALUES&lt;/span&gt; (&lt;/span&gt;
&lt;span id=&quot;cb5-7&quot;&gt;&lt;a href=&quot;#cb5-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;co&quot;&gt;/* whatever event source data*/&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-8&quot;&gt;&lt;a href=&quot;#cb5-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;st&quot;&gt;&amp;#39;{&amp;quot;email&amp;quot;:&amp;quot;hi@jappie.me&amp;quot;}&amp;#39;&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&amp;#39;create-user&amp;#39;&lt;/span&gt;, now());&lt;/span&gt;
&lt;span id=&quot;cb5-9&quot;&gt;&lt;a href=&quot;#cb5-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;INTO&lt;/span&gt; event_last_applied (&lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt;, event_id)&lt;/span&gt;
&lt;span id=&quot;cb5-10&quot;&gt;&lt;a href=&quot;#cb5-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;fu&quot;&gt;max&lt;/span&gt;(&lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;FROM&lt;/span&gt; event&lt;/span&gt;
&lt;span id=&quot;cb5-11&quot;&gt;&lt;a href=&quot;#cb5-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;ON&lt;/span&gt; CONFLICT (&lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb5-12&quot;&gt;&lt;a href=&quot;#cb5-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    DO &lt;span class=&quot;kw&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;SET&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-13&quot;&gt;&lt;a href=&quot;#cb5-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        event_id &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; lastval();&lt;/span&gt;
&lt;span id=&quot;cb5-14&quot;&gt;&lt;a href=&quot;#cb5-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-15&quot;&gt;&lt;a href=&quot;#cb5-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;/* left out projection code, connect user to company */&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-16&quot;&gt;&lt;a href=&quot;#cb5-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-17&quot;&gt;&lt;a href=&quot;#cb5-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;INTO&lt;/span&gt; event (payload, &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt;, created)&lt;/span&gt;
&lt;span id=&quot;cb5-18&quot;&gt;&lt;a href=&quot;#cb5-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;VALUES&lt;/span&gt; (&lt;/span&gt;
&lt;span id=&quot;cb5-19&quot;&gt;&lt;a href=&quot;#cb5-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;co&quot;&gt;/* whatever event source data*/&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-20&quot;&gt;&lt;a href=&quot;#cb5-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;st&quot;&gt;&amp;#39;{&amp;quot;company-id&amp;quot;:2, &amp;quot;user-id&amp;quot;: 1}&amp;#39;&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&amp;#39;connect-company&amp;#39;&lt;/span&gt;, now());&lt;/span&gt;
&lt;span id=&quot;cb5-21&quot;&gt;&lt;a href=&quot;#cb5-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;INTO&lt;/span&gt; event_last_applied (&lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt;, event_id)&lt;/span&gt;
&lt;span id=&quot;cb5-22&quot;&gt;&lt;a href=&quot;#cb5-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;fu&quot;&gt;max&lt;/span&gt;(&lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;FROM&lt;/span&gt; event&lt;/span&gt;
&lt;span id=&quot;cb5-23&quot;&gt;&lt;a href=&quot;#cb5-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;ON&lt;/span&gt; CONFLICT (&lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb5-24&quot;&gt;&lt;a href=&quot;#cb5-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    DO &lt;span class=&quot;kw&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;SET&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-25&quot;&gt;&lt;a href=&quot;#cb5-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        event_id &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; lastval();&lt;/span&gt;
&lt;span id=&quot;cb5-26&quot;&gt;&lt;a href=&quot;#cb5-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;COMMIT&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Transactions form proper &lt;a href=&quot;https://hackage.haskell.org/package/base-4.17.0.0/docs/Data-Monoid.html&quot;&gt;monoids&lt;/a&gt;, and they can grow arbitrarily large. This is good because even for large chuncks of business logic we always gaurantee our event log remains in a valid state. We’d expect our re-projections to always work, because only correct ones get recorded. Where does this go wrong then?&lt;/p&gt;
&lt;p&gt;The issue is concurrency, consider connection &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;code&gt;A&lt;/code&gt; opens a transaction and inserts a user, but has to do other projections and event insertions as well&lt;/li&gt;
&lt;li&gt;&lt;code&gt;B&lt;/code&gt; opens a transaction and wants to insert an event, &lt;code&gt;B&lt;/code&gt; has to wait until &lt;code&gt;A&lt;/code&gt; completes. This is because &lt;code&gt;A&lt;/code&gt; made an update to the &lt;code&gt;event_last_applied&lt;/code&gt; on row number &lt;code&gt;1&lt;/code&gt;, as part of the insert event logic. This row is locked until &lt;code&gt;A&lt;/code&gt; completes, so &lt;code&gt;B&lt;/code&gt; has to wait.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;A&lt;/code&gt; completes and releases the lock on row &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;B&lt;/code&gt; can now complete as well.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is not a deadlock as long as &lt;code&gt;A&lt;/code&gt; completes. &lt;code&gt;B&lt;/code&gt; can wait a long time because our transactions can grow arbitrarily large. For example when we’re inserting millions of rows of data, taking up half an hour. Which is far beyond the HTTP session length of 30 seconds, or whatever length a user finds acceptable. This was indeed the production bug encountered at &lt;a href=&quot;https://supercede.com/&quot;&gt;supercede&lt;/a&gt;. One user was doing pack ingestion, which involves reading millions of excell file rows, and the rest of the system became unusable because of that.&lt;/p&gt;
&lt;h2 id=&quot;now-what&quot;&gt;Now what?&lt;/h2&gt;
&lt;p&gt;At first I started with the most obvious solution. I re-grouped how event sourcing took place. I put the event sourcing code at the end of the transaction in pack ingestion, so that the event source table remained available for other transactions up till that point. Because event sourcing is only a small part of normal transactions, this created a small locking window. Thus this worked! However it only worked for this transaction with pack ingestation, I didn’t know if there were any other transactions like this in our code base. Furthermore, I had to bypass parts of the event sourcing interface to make this work. For example, I had to project events by hand, and insert events by hand, rather then using the internal library. I decided this was a bad precedence to set. I was afraid other engineers would copy this approach when it wasn’t necessary. So I went looking for other solutions.&lt;/p&gt;
&lt;p&gt;Another idea is that instead of doing the large transaction, we could split it up into smaller ones. Allowing other events to clear while this bigger one was in progress. I didn’t like this either. For one this code was old, tried and tested, making a rather large modification like splitting the transaction could introduce many unintended bugs. For example when cleanup doesn’t happen correctly on failure. I thought this was likely because this transaction was large, and covered many tables. Also our normal tools such as types and integration tests wouldn’t help a lot with guaranteeing cleanup. So this would become difficult to maintain fast. Which is problematic for a piece of code which is the “money maker”, and needs to change often. Furthermore I had a much more simple but thorough solution in mind.&lt;/p&gt;
&lt;p&gt;I decided to redesign the event source tables. Naturally my colleagues exclaimed shouts of joy when I decided to modify an even older system. The event source system described above is almost as old as supercede. But I believed it was easier to modify, and more importantly, easier to test for correctness. Furthermore this would also solve the problem for other, possibly unknown, or future, large transactions. This change would keep our code easy to maintain and solve a bug. The new schema looks almost identical to the old one:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode sql&quot;&gt;&lt;code class=&quot;sourceCode sql&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;#cb6-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;TABLE&lt;/span&gt; event (&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;#cb6-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt; serial &lt;span class=&quot;kw&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;#cb6-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    payload jsonb &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;#cb6-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;character&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;varying&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;#cb6-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    created &lt;span class=&quot;dt&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;zone&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-6&quot;&gt;&lt;a href=&quot;#cb6-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;);&lt;/span&gt;
&lt;span id=&quot;cb6-7&quot;&gt;&lt;a href=&quot;#cb6-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-8&quot;&gt;&lt;a href=&quot;#cb6-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;TABLE&lt;/span&gt; event_applied (&lt;/span&gt;
&lt;span id=&quot;cb6-9&quot;&gt;&lt;a href=&quot;#cb6-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt; serial &lt;span class=&quot;kw&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb6-10&quot;&gt;&lt;a href=&quot;#cb6-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    event_id bigint &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;REFERENCES&lt;/span&gt; event (&lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt;),&lt;/span&gt;
&lt;span id=&quot;cb6-11&quot;&gt;&lt;a href=&quot;#cb6-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    created &lt;span class=&quot;dt&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;zone&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-12&quot;&gt;&lt;a href=&quot;#cb6-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The big difference is that we renamed &lt;code&gt;event_last_applied&lt;/code&gt; to &lt;code&gt;event_applied&lt;/code&gt; and added a created field. With this change, inserting events is also quite similar to the initial system:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode sql&quot;&gt;&lt;code class=&quot;sourceCode sql&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;#cb7-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;cf&quot;&gt;BEGIN&lt;/span&gt;;&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;#cb7-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;INTO&lt;/span&gt; event (payload, &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt;, created)&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;#cb7-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;VALUES&lt;/span&gt; (&lt;span class=&quot;st&quot;&gt;&amp;#39;{&amp;quot;email&amp;quot;:&amp;quot;hi@jappie.me&amp;quot;}&amp;#39;&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&amp;#39;create-user&amp;#39;&lt;/span&gt;, now());&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;#cb7-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;INTO&lt;/span&gt; event_applied (event_id, created)&lt;/span&gt;
&lt;span id=&quot;cb7-5&quot;&gt;&lt;a href=&quot;#cb7-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;last_value&lt;/span&gt;, now() &lt;span class=&quot;kw&quot;&gt;FROM&lt;/span&gt; event_id_seq;&lt;/span&gt;
&lt;span id=&quot;cb7-6&quot;&gt;&lt;a href=&quot;#cb7-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;COMMIT&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The big difference is that instead of modifying always row number 1 to be the latest ID, we insert a new row into &lt;code&gt;event_applied&lt;/code&gt; with the latest id. This avoids locking of row number 1. For re-projection we truncate the &lt;code&gt;event_applied&lt;/code&gt; table, allowing the code to rerun all those events. The big difference is in figuring out which events haven’t been applied yet:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode sql&quot;&gt;&lt;code class=&quot;sourceCode sql&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;#cb8-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt;, payload &lt;span class=&quot;kw&quot;&gt;FROM&lt;/span&gt; event &lt;span class=&quot;kw&quot;&gt;AS&lt;/span&gt; e&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;#cb8-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;WHERE&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;#cb8-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;EXISTS&lt;/span&gt; (&lt;/span&gt;
&lt;span id=&quot;cb8-4&quot;&gt;&lt;a href=&quot;#cb8-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;FROM&lt;/span&gt; event_applied&lt;/span&gt;
&lt;span id=&quot;cb8-5&quot;&gt;&lt;a href=&quot;#cb8-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;WHERE&lt;/span&gt; event_id &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; e.&lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb8-6&quot;&gt;&lt;a href=&quot;#cb8-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;BY&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-7&quot;&gt;&lt;a href=&quot;#cb8-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;ASC&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We compare the event table to the &lt;code&gt;event_applied&lt;/code&gt; table, and return any events that don’t exist in that. We’re still ordering by id to ensure the correct order. &lt;span id=&quot;is-this-correct&quot;&gt;Is this correct?&lt;/span&gt; Let’s consider concurrency once more with connection &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;code&gt;A&lt;/code&gt; opens a transaction and inserts a user, but has to do other event source queries as well.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;B&lt;/code&gt; opens a transaction does it’s projection work and wants to insert an event, &lt;code&gt;B&lt;/code&gt; creates a new row in the &lt;code&gt;even_applied&lt;/code&gt; table and completes. There is no need to wait since there is no single row lock. So &lt;code&gt;B&lt;/code&gt; finishes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;A&lt;/code&gt; finishes it’s other event sourcing completes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This doesn’t deadlock. However it’s not completely correct in that &lt;code&gt;A&lt;/code&gt; get’s id 1. and &lt;code&gt;B&lt;/code&gt; get’s id 2, but &lt;code&gt;A&lt;/code&gt;’s transaction finishes after &lt;code&gt;B&lt;/code&gt; by inserting another event with id 3. So on reprojection one of &lt;code&gt;A&lt;/code&gt;’s events get’s applied before &lt;code&gt;B&lt;/code&gt;. But in the initial projection, all of &lt;code&gt;A&lt;/code&gt;’s event happened &lt;em&gt;after&lt;/em&gt; &lt;code&gt;B&lt;/code&gt;. So the first event of &lt;code&gt;A&lt;/code&gt; is out of order. This &lt;em&gt;may&lt;/em&gt; cause issues. This problem was also present in the original implementation, since an id is acquired before the lock waiting happens. I think a solution would be to group the events by transaction id, and then order by last created event. In this case all events created before &lt;code&gt;B&lt;/code&gt; in &lt;code&gt;A&lt;/code&gt;’s transaction would be pushed behind it by an event happening after &lt;code&gt;B&lt;/code&gt; finishes. If we do that, the event table gets an extra field:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode sql&quot;&gt;&lt;code class=&quot;sourceCode sql&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;#cb9-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;TABLE&lt;/span&gt; event (&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;#cb9-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt; serial &lt;span class=&quot;kw&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;#cb9-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    payload jsonb &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb9-4&quot;&gt;&lt;a href=&quot;#cb9-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;character&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;varying&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb9-5&quot;&gt;&lt;a href=&quot;#cb9-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    created &lt;span class=&quot;dt&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;zone&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb9-6&quot;&gt;&lt;a href=&quot;#cb9-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    transaction_id bigint &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-7&quot;&gt;&lt;a href=&quot;#cb9-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Our insert function retrieves the transaction id with &lt;a href=&quot;https://www.postgresql.org/docs/9.0/functions-info.html#FUNCTIONS-TXID-SNAPSHOT&quot;&gt;&lt;code&gt;txid_current&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode sql&quot;&gt;&lt;code class=&quot;sourceCode sql&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;#cb10-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;cf&quot;&gt;BEGIN&lt;/span&gt;;&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;#cb10-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;INTO&lt;/span&gt; event (payload, &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt;, created, transaction_id)&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;#cb10-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;VALUES&lt;/span&gt; (&lt;span class=&quot;st&quot;&gt;&amp;#39;{&amp;quot;email&amp;quot;:&amp;quot;hi@jappie.me&amp;quot;}&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-4&quot;&gt;&lt;a href=&quot;#cb10-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           , &lt;span class=&quot;st&quot;&gt;&amp;#39;create-user&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-5&quot;&gt;&lt;a href=&quot;#cb10-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           , now()&lt;/span&gt;
&lt;span id=&quot;cb10-6&quot;&gt;&lt;a href=&quot;#cb10-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           , txid_current());&lt;/span&gt;
&lt;span id=&quot;cb10-7&quot;&gt;&lt;a href=&quot;#cb10-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;INTO&lt;/span&gt; event_applied (event_id, created)&lt;/span&gt;
&lt;span id=&quot;cb10-8&quot;&gt;&lt;a href=&quot;#cb10-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;last_value&lt;/span&gt;, now() &lt;span class=&quot;kw&quot;&gt;FROM&lt;/span&gt; event_id_seq;&lt;/span&gt;
&lt;span id=&quot;cb10-9&quot;&gt;&lt;a href=&quot;#cb10-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;COMMIT&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And our unnaplied events query now groups:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb11&quot;&gt;&lt;pre class=&quot;sourceCode sql&quot;&gt;&lt;code class=&quot;sourceCode sql&quot;&gt;&lt;span id=&quot;cb11-1&quot;&gt;&lt;a href=&quot;#cb11-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;SELECT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-2&quot;&gt;&lt;a href=&quot;#cb11-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    array_agg(&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;types&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb11-3&quot;&gt;&lt;a href=&quot;#cb11-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    array_agg(payload) &lt;span class=&quot;kw&quot;&gt;AS&lt;/span&gt; payloads&lt;/span&gt;
&lt;span id=&quot;cb11-4&quot;&gt;&lt;a href=&quot;#cb11-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;FROM&lt;/span&gt; event &lt;span class=&quot;kw&quot;&gt;AS&lt;/span&gt; e&lt;/span&gt;
&lt;span id=&quot;cb11-5&quot;&gt;&lt;a href=&quot;#cb11-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;EXISTS&lt;/span&gt; (&lt;/span&gt;
&lt;span id=&quot;cb11-6&quot;&gt;&lt;a href=&quot;#cb11-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;kw&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;FROM&lt;/span&gt; event_applied &lt;span class=&quot;kw&quot;&gt;WHERE&lt;/span&gt; event_id &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; e.&lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-7&quot;&gt;&lt;a href=&quot;#cb11-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;
&lt;span id=&quot;cb11-8&quot;&gt;&lt;a href=&quot;#cb11-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;GROUP&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;BY&lt;/span&gt; transaction_id&lt;/span&gt;
&lt;span id=&quot;cb11-9&quot;&gt;&lt;a href=&quot;#cb11-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;max&lt;/span&gt;(&lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;ASC&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we run that unnaplied events query on an event table like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;id |        payload        |      type       | created    | transaction_id 
---+-----------------------+-----------------+------------+----------------
 6 | {email: hi@jappie.me} | delete-user     | 2023-01-15 | 77958
 7 | {email: hi@jappie.me} | create-user     | 2023-01-15 | 77959
 8 | {company-id: 2}       | delete-company  | 2023-01-15 | 77958&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’d get a result like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;             types             |              payloads
-------------------------------+-----------------------------------------
 {create-user}                 | {{email: &amp;#39;hi@jappie.me&amp;#39;}}
 {delete-user,delete-company}  | {{email: &amp;#39;hi@jappie.me&amp;#39;},{company-id: 2}}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which is what we want. Even though the create user event happened while the delete user event was happening, the delete user event was part of a larger transaction. So the create user even should come first when re-projecting. This allows arbitrary sized transactions to project alongside each-other and provides better ordering guarantees then the original implementation.&lt;/p&gt;
&lt;h2 id=&quot;closing-thoughts&quot;&gt;Closing thoughts&lt;/h2&gt;
&lt;p&gt;Phew, that was a lot. I didn’t think this would become such a large post. Designing an event source system on Postgres transactions is rather hard. All I wanted to do is clear my thoughts on the matter, but that grouping issue is another bug I just found by writing about this 😅.&lt;/p&gt;
&lt;p&gt;I think the biggest lesson I’ve (re)learned from the deadlock bug itself is to make sure you reproduce an issue first before diving into solutions. Even nasty business threatening system level bugs like these can sometimes be solved with some minor modifications to the system. If we had skipped this small step of reproducing the issue, we may have focused on the CPU observation and moved pack ingestation to a separate machine, which would’ve taken weeks to implement and not solve anything.&lt;/p&gt;
&lt;p&gt;Furthermore, it’s humbling to see that even after having used relational databases for more then a decade, I still can learn new things about them. For example Postgres’ auto increment sidesteps the transaction, which was quite shocking to me. A rather important detail to keep in mind when reasoning about these systems.&lt;/p&gt;
&lt;p&gt;I made a &lt;a href=&quot;https://github.com/jappeace/MAHDB&quot;&gt;github repository&lt;/a&gt; for playing around with the queries more easily. I hope you enjoyed this article, please leave a comment if you have any questions or suggestions below.&lt;/p&gt;
&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&quot;https://github.com/jappeace/MAHDB&quot;&gt;code&lt;/a&gt; in this &lt;a href=&quot;https://github.com/jappeace/MAHDB&quot;&gt;blogpost&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Postgres &lt;a href=&quot;https://wiki.postgresql.org/wiki/Lock_Monitoring&quot;&gt;Lock monitoring&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://garba.org/posts/2016/event-sourcing/#materialised-view-pattern&quot;&gt;Blogs&lt;/a&gt; on &lt;a href=&quot;https://www.ahri.net/2019/07/practical-event-driven-and-sourced-programs-in-haskell/&quot;&gt;event sourcing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Presentation on &lt;a href=&quot;https://www.youtube.com/watch?v=8JKjvY4etTY&quot;&gt;event sourcing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Summerhouse Paradis Aruba</title>
    <link href="https://jappieklooster.nl/summerhouse-paradis-aruba.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2023-01-12:/summerhouse-paradis-aruba.html</id>
    <published>2023-01-12T19:00:00Z</published>
    <updated>2023-01-12T19:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="story"/>
    <summary type="html">&lt;style&gt;
.video{
    width: 100%;
    height: 20em;
}
&lt;/style&gt;
&lt;p&gt;This post tracks the progress of a rental property I bought on Aruba. The goal is to rent it out short term to tourists. This video gives a rough overview of the current status:&lt;/p&gt;
&lt;iframe class=&quot;video&quot; src=&quot;https://www.youtube.com/embed/V4p4mF6N4pc&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&gt;
&lt;/iframe&gt;
&lt;h2 id=&quot;summerhouse-paradis-on-aruba-vlog-colors-mold-and-a-hole&quot;&gt;Summerhouse paradis on aruba vlog: Colors, mold and a hole&lt;/h2&gt;</summary>
    <content type="html">&lt;style&gt;
.video{
    width: 100%;
    height: 20em;
}
&lt;/style&gt;
&lt;p&gt;This post tracks the progress of a rental property I bought on Aruba. The goal is to rent it out short term to tourists. This video gives a rough overview of the current status:&lt;/p&gt;
&lt;iframe class=&quot;video&quot; src=&quot;https://www.youtube.com/embed/V4p4mF6N4pc&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&gt;
&lt;/iframe&gt;
&lt;h2 id=&quot;summerhouse-paradis-on-aruba-vlog-colors-mold-and-a-hole&quot;&gt;Summerhouse paradis on aruba vlog: Colors, mold and a hole&lt;/h2&gt;
&lt;p&gt;A week later and we’re starting to work on the pool.&lt;/p&gt;
&lt;iframe class=&quot;video&quot; src=&quot;https://www.youtube.com/embed/cyyV7WXNnEE&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&gt;
&lt;/iframe&gt;
&lt;h2 id=&quot;how-do-you-even-build-a-pool-summerhouse-paradis-vlog-iii-2022-12-18&quot;&gt;How do you even build a pool? Summerhouse paradis vlog III, 2022-12-18&lt;/h2&gt;
&lt;p&gt;Once again, a week later, my final week on Aruba, and the pool is almost concrete.&lt;/p&gt;
&lt;iframe class=&quot;video&quot; src=&quot;https://www.youtube.com/embed/ck1uogmzXjE&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&gt;
&lt;/iframe&gt;</content>
  </entry>
  <entry>
    <title>Why do I still write this blog?</title>
    <link href="https://jappieklooster.nl/why-do-i-still-write-this-blog.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2023-01-11:/why-do-i-still-write-this-blog.html</id>
    <published>2023-01-11T17:10:00Z</published>
    <updated>2023-01-11T17:10:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;p&gt;My motivation for blogging has changed over time. I’d like to revisit my initial reason, and discuss how this changed while maintaining the blog. After all I keep posting articles on here, something has to keep me going right?&lt;/p&gt;
&lt;p&gt;We can read my original &lt;a href=&quot;https://jappie.me/website-launch.html#why-make-a-site&quot;&gt;motivation&lt;/a&gt;. The initial goal was&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;My motivation for blogging has changed over time. I’d like to revisit my initial reason, and discuss how this changed while maintaining the blog. After all I keep posting articles on here, something has to keep me going right?&lt;/p&gt;
&lt;p&gt;We can read my original &lt;a href=&quot;https://jappie.me/website-launch.html#why-make-a-site&quot;&gt;motivation&lt;/a&gt;. The initial goal was to make money apparently&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;, through ads or Patreon. T-That didn’t work out so well. I now realize it’s quite hard to make money with blogging, you’ve to be really good! I’m not, and that’s okay. Furthermore from ads you need tons of visitors to get even the smallest amount of money. And for patreon to work you need to make something for a niche audience, and captivate them, I think at the time I didn’t really know what that would entail. Similar to patreon would be to use &lt;a href=&quot;https://stratechery.com/2021/sovereign-writers-and-substack/&quot;&gt;substack&lt;/a&gt;, however that didn’t exist at the time.&lt;/p&gt;
&lt;p&gt;Another romantic desire not listed in &lt;a href=&quot;https://jappie.me/website-launch.html#why-make-a-site&quot;&gt;that post&lt;/a&gt; was being remembered after my death. For example consider “Commentarii de Bello Gallico” (Commentaries on the Gallic War). People still read that 2000 years after Ceasars’ death. I was fascinated by this idea, to have your words echo trough the ages.&lt;/p&gt;
&lt;p&gt;To achieve this I knew my writing skill had to improve. I hoped that trough blogging I’d get better. I knew my first posts wouldn’t be interesting or engaging, but I could learn from each post. So once I got this going, I placed google analytics on it, and soon realized no-one was reading this blog. I published something on the internet and no-one was reading this! I gained some solace from having carved out my own private corner, so cozy just for me. I learned at the beginning of 2017 the internet was already too big. Still my goal was to be an attention whore, and to get that you /need/ to post your content on aggregator websites like reddit or Facebook (depending on your audience). Peeps aren’t going to type in &lt;code&gt;jappie.me&lt;/code&gt; magically in the URL bar, and Google ain’t just gonna find you without some links pointing to you.&lt;/p&gt;
&lt;p&gt;Getting a big name that last trough the ages was a goal of Jappie from 2017/2018, I don’t think this is no longer a goal of mine. Once I’m dead, well, I’m dead. You can remember me all you want, that ain’t gonna bring me back, and who wants to go back anyway?&lt;/p&gt;
&lt;h2 id=&quot;great-compromise&quot;&gt;Great compromise&lt;/h2&gt;
&lt;p&gt;Although my desire for being remembered has faded, I still want to get better at writing. Because I feel this still covers up flaws I have. For example, I’m quite bad at self promotion. I started seeing blogging as a sort of propaganda machine &lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;, that would represent me so I didn’t have to. In real life&lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; social interactions, I often come across as doubtful on my skills, and I’ve trouble of thinking what to say in conversations. Furthermore, I don’t enjoy convincing that others I’m any good at anything, because that feels like bragging to me. However, as a programmer you pretty have to do this. For example during an interview, or when trying to get another assignment.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;So rather then changing my personality, I realized I could get better at writing, The blog was a great compromise.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ironically, trough writing I discovered I enjoy writing. I get a lot of pleasure out of being precise. Merely putting my thoughts onto paper is apparently a step up in precision and clarity. It’s quite shocking and enlightening at the same, to see how chaotic and rambly your own thoughts are once you start putting them in words on paper. After a mere day of writing a passage you may question who wrote that, because it looks so foreign to you. This is especially true with fleeting thoughts.&lt;/p&gt;
&lt;p&gt;But I’ve also noticed that converse on topics I’ve written about is quite easy. This has been a huge benefit for me. No longer I’ve to think of what to say, but I can fully focus on how to say it. Especially during interviews where the other party has decided to read what you’ve written about. In those cases, conversation becomes a breeze! This truly is an unintended consequence, but I guess blogging has helped my career.&lt;/p&gt;
&lt;h2 id=&quot;frustration&quot;&gt;Frustration&lt;/h2&gt;
&lt;p&gt;Another use of blogging is letting out professional frustration in a constructive manner. For example the &lt;a href=&quot;https://jappie.me/failing-in-haskell.html&quot;&gt;failing in haskell&lt;/a&gt; post was directly due to error handling encounters in professional code bases. Explaining this in painful detail.&lt;/p&gt;
&lt;p&gt;This also happened with the stack &lt;a href=&quot;https://jappie.me/fun-with-stack-haskell-dependency-management.html&quot;&gt;dependency management&lt;/a&gt; post at the time. Both these posts have seen a lot of user interaction as well, people started debating about it on reddit or hackernews for example. So not only does this help me vent, it also gets my name out there! However I feel it’s not the best idea to become a divisive-andy. Because I don’t think it’s an explicit goal of me right now is to make this blog popular. After all this is &lt;em&gt;my&lt;/em&gt; corner of the internet. I like the feeling of putting words out there that no-one reads. Making this blog popular would put pressure on me to write popular content. But I want to write abut what &lt;em&gt;I&lt;/em&gt; want to write, not what’s popular. I could’ve written more about elm for example, because that &lt;a href=&quot;https://jappie.me/elm-on-fire-shaders-in-elm.html&quot;&gt;elm on fire&lt;/a&gt; post was quite successful. But after making fire, my interest faded, and so did my motivation.&lt;/p&gt;
&lt;p&gt;I did notice however that once I got a blog post out on something which frustrates me, the frustration goes away. It simply no longer bothers me, because as far as I’m aware this is the most impactful thing I can do to solve an issue. If publicly complaining about something, putting my name on the line, doesn’t help, what will?&lt;/p&gt;
&lt;h2 id=&quot;nostalgia&quot;&gt;Nostalgia&lt;/h2&gt;
&lt;p&gt;Interestingly I noticed another reason to blog lately. I enjoy reading back my old articles! Remember that time I immigrated &lt;a href=&quot;https://jappie.me/jappie-lives-with-kangaroos.html&quot;&gt;to australia&lt;/a&gt; for a year to do programming there? Or doing a cute lil’ &lt;a href=&quot;https://jappie.me/tool-survey.html&quot;&gt;tool survey&lt;/a&gt; back in 2017 for example. At the time I thought I was using some awesome stuff. Now I know it’s a rather basic setup. My nixos &lt;a href=&quot;https://jappie.me/the-nix-mutli-monolith-machine-nmmm.html&quot;&gt;based configuration&lt;/a&gt; is far more powerful and flexible for example.&lt;/p&gt;
&lt;p&gt;I should make more of these slice of live posts. I’ve been only doing technical stuff the last couple of years, and to be honest, I like writing about my own live as well.&lt;/p&gt;
&lt;h2 id=&quot;interesting-challenge&quot;&gt;Interesting Challenge&lt;/h2&gt;
&lt;p&gt;It’s one thing to write a coherent story, it’s another thing to make that story interesting. Imagine shakespeare being writtin as a cooking book:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Start the thunder and lightening. Grab a first witch, a second witch and a third witch. Let the first witch say: When shall we tree meet again, in thunder lightening or rain.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It’s boring! Just like when talking about programming, we need to make it interesting. The solutions described in programing langauges are meant for machine consumption mostly, writing them down in natural langauge is a completly different excersize. You can be much more lax in natural langauge than in programming. A misspelled word? That’s fine, the reader will be a bit frustrated but it doesn’t break the meaning of the story. You can’t get away with that in programming.&lt;/p&gt;
&lt;p&gt;However, in programming you don’t have the problem of keeping your audiences’ attention. Are you using a disgusting font on your blog? No-one is going to read that. Are you re-using the same vocab over and over? I’m gonna stop. You need to write interestingly, which is much harder than just doing something grammatically correct.&lt;/p&gt;
&lt;p&gt;This is what most business writers don’t get. Dumping a bunch of jargon in your post is going to shoo away people. Using politically correct opinions is boring. You have to take a position to attract an audience. This is hard.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I write for self promotion, to vent, and for fun. I think writing is difficult, but I enjoy it. Writing something interesting is even harder, but I feel it’s well worth the exercise.&lt;/p&gt;
&lt;p&gt;Do you feel writing is fun, or perhaps boring? Or do you also have a blog? Please let me know in the comments below!&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;I long had forgotten this was a serious goal of mine.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;Very much like “Commentarii de Bello Gallico”, which more realistically should’ve been called the genocide of the Gallic people.&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;Offline interactions&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Zurich hack 2022 Denotational Design</title>
    <link href="https://jappieklooster.nl/zurich-hack-2022-denotational-design.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2022-09-26:/zurich-hack-2022-denotational-design.html</id>
    <published>2022-09-26T19:00:00Z</published>
    <updated>2022-09-26T19:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="technique"/>
    <summary type="html">&lt;style&gt;
img[alt=&quot;zurich hack logo, uwu&quot;]{
  width:40%;
  margin-left: 30%;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;img src=&quot;images/2022/zurich-hack.svg&quot; alt=&quot;zurich hack logo, uwu&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;zurich hack logo, uwu&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This blog post and after action report is three months overdue, but I participated in &lt;a href=&quot;https://zfoh.ch/zurihac2022/&quot;&gt;Zurich hack 2022&lt;/a&gt;. Zurich hack is a voluntary hackaton organized in &lt;a href=&quot;https://www.myswitzerland.com/en/destinations/rapperswil-jona/&quot;&gt;Rapperswil-Jona&lt;/a&gt; &lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;, with as theme improving the Haskell ecosystem and&lt;/p&gt;</summary>
    <content type="html">&lt;style&gt;
img[alt=&quot;zurich hack logo, uwu&quot;]{
  width:40%;
  margin-left: 30%;
}
&lt;/style&gt;
&lt;figure&gt;
&lt;img src=&quot;images/2022/zurich-hack.svg&quot; alt=&quot;zurich hack logo, uwu&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;zurich hack logo, uwu&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This blog post and after action report is three months overdue, but I participated in &lt;a href=&quot;https://zfoh.ch/zurihac2022/&quot;&gt;Zurich hack 2022&lt;/a&gt;. Zurich hack is a voluntary hackaton organized in &lt;a href=&quot;https://www.myswitzerland.com/en/destinations/rapperswil-jona/&quot;&gt;Rapperswil-Jona&lt;/a&gt; &lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;, with as theme improving the Haskell ecosystem and socializing. Naturally I chose to work on the most research-y project I could find. Sandy was happy to oblige with his &lt;a href=&quot;https://zfoh.ch/zurihac2022/projects.html#denotational-design&quot;&gt;denotational design&lt;/a&gt; project. Here we build an “infinite” baseless chip design, with a &lt;a href=&quot;https://en.wikipedia.org/wiki/Homomorphism&quot;&gt;homomorphism&lt;/a&gt; in natural numbers to proof correctness, more on this in the proofs and programs section.&lt;/p&gt;
&lt;p&gt;Our presentation was surprisingly good considering we slapped it together in 30 minutes. However, I think we could’ve done a better job at explaining denotational design, and we could’ve elaborated more on why proving matters. I shall use this post to fill in these gaps. For starters the presentation can be seen here:&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/fCT0uVCe53Q?start=682&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;
&lt;/iframe&gt;
&lt;p&gt;I helped presenting&lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;, however most of the implementation was done by Sandy and Nathan. I wish I could’ve done more, but my Agda isn’t good enough yet. I helped with cheering on their proving efforts and coming up with ideas for the design.&lt;/p&gt;
&lt;h2 id=&quot;denotational-design&quot;&gt;Denotational design&lt;/h2&gt;
&lt;p&gt;Let’s begin on what denotational design is. You could watch a &lt;a href=&quot;https://youtu.be/bmKYiUOEo2A?t=871&quot;&gt;video on this&lt;/a&gt;, but summarized in my own words:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We should decompose parts when possible.&lt;/li&gt;
&lt;li&gt;Abstractions shouldn’t leak.&lt;/li&gt;
&lt;li&gt;We should look for elegance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first point is “We should decompose parts when possible”. This means breaking up our design in such a way we can re-use parts into a larger whole. For example in Zurich hack, our first designs was a large record for multiplication that had everything baked into it. Then someone had the idea to split that record into a separate addition and multiplication records and re-express multiplication into addition. This allows us to work with the simpler problem of addition, before tackling multiplication. Which is what we eventually settled upon as well. I don’t think decomposition has been stated as an explicit goal of denotational design before, but it feels implied. Perhaps in &lt;a href=&quot;https://youtu.be/bmKYiUOEo2A?t=871&quot;&gt;Conals talk&lt;/a&gt;, “principled construction of correct implementation” can be interpreted as such.&lt;/p&gt;
&lt;p&gt;The point about “Abstractions shouldn’t leak” is quite interesting. We wish to provided a simplified view of the world to the user through abstraction. In practice this means we should hide the implementation from the user. I once suggested for example to add a xor operation to our record to get rid of the carry bit in certain cases. After some discussion we settled on not doing this because xor isn’t really a thing you care about when thinking in terms of semirings&lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;. In other words, when thinking in terms of multiplication and addition, you don’t want to care about the bit representation. For more examples of “abstractions shouldn’t leak” I recommend the book &lt;a href=&quot;https://algebradriven.design/&quot;&gt;algebra driven design&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The final point is “We should look for elegance”. Which should serve as a compass upon iteration. Here again I’ve an example from just after Zurich hack: The overflow bit in our addition record bugged me. It kind off exposes the internals of addition. So I decided to delete it in favor of doing a full co-product instead. Doing this would break both multiplication and addition records, the proofs have to be redone, I’m not even sure if it’s possible. So there is definitely a cost. &lt;a href=&quot;#fn4&quot; class=&quot;footnote-ref&quot; id=&quot;fnref4&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; However I like that design, it’s more elegant because this would make multiplication have a product type as input, and addition a sum type. Which would have some nice symmetry. This is something we didn’t drive home enough in the Zurich hack presentation. The proof we presented looked impressive, but this isn’t something you necessarily want. An elegant proof and design is what you want.&lt;/p&gt;
&lt;h2 id=&quot;proofs-and-programs&quot;&gt;Proofs and programs&lt;/h2&gt;
&lt;p&gt;I pondered on proofs in software and how dependent types interplay. Is the design I dreamed up correct? How do you know this? We used a property called a &lt;a href=&quot;https://en.wikipedia.org/wiki/Homomorphism&quot;&gt;homomorphism&lt;/a&gt; to prove correctness. In mortal words, our chip design was interpreted into &lt;a href=&quot;https://en.wikipedia.org/wiki/Natural_number&quot;&gt;natural numbers&lt;/a&gt; and we showed that addition and multiplication would be the same for our chip, as it is in natural numbers.&lt;/p&gt;
&lt;p&gt;To start talking about proofs, we need a design and implementation to proof correctness for. In our case this was a chip design in Agda. This Adder&lt;a href=&quot;#fn5&quot; class=&quot;footnote-ref&quot; id=&quot;fnref5&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt; is something we settled upon after several iterations of design, but I’m cutting that part out for brevity:&lt;a href=&quot;#fn6&quot; class=&quot;footnote-ref&quot; id=&quot;fnref6&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;6&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;record&lt;/span&gt; Adder &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;τ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;size &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; τ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Fin size&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;constructor&lt;/span&gt; adds&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;field&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    add &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; Fin &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; × τ × τ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; τ × Fin &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- 1&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;#cb1-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    zeroA &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; τ &lt;span class=&quot;co&quot;&gt;-- 2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;#cb1-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    proof-add &lt;span class=&quot;co&quot;&gt;-- 3&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;#cb1-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;mnp &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; Fin &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; × τ × τ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;#cb1-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; toℕ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;digitize &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;P&lt;span class=&quot;ot&quot;&gt;.&lt;/span&gt;map μ id &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;add mnp&lt;span class=&quot;ot&quot;&gt;)))&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;#cb1-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      ≡ toℕ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;addF&amp;#39;3 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;P&lt;span class=&quot;ot&quot;&gt;.&lt;/span&gt;map id &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;P&lt;span class=&quot;ot&quot;&gt;.&lt;/span&gt;map μ μ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; mnp&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb1-10&quot;&gt;&lt;a href=&quot;#cb1-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;open&lt;/span&gt; Adder&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we’re saying, to define an adder you need 3 things. You need an add operation &lt;code&gt;1&lt;/code&gt;, you need a zero &lt;code&gt;2&lt;/code&gt; &lt;a href=&quot;#fn7&quot; class=&quot;footnote-ref&quot; id=&quot;fnref7&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;7&lt;/sup&gt;&lt;/a&gt;, and you need a proof of addition &lt;code&gt;3&lt;/code&gt;. The proof of addition is the homomorphism from our chip to the natural numbers. Furthermore we don’t specify the input type, which is represented by &lt;code&gt;τ&lt;/code&gt;. This is done because we want a baseless chip design. We’re fine with arbitrary inputs, As long as we can interpreted this, represented by &lt;code&gt;μ&lt;/code&gt;. In &lt;code&gt;μ&lt;/code&gt; the &lt;code&gt;Fin size&lt;/code&gt; indicates a finite size, which we need because we want to map our design to the real world, which is finite.&lt;/p&gt;
&lt;p&gt;Not shown from the record is that we’re able to make a bigger adder out of a smaller one trough composition of two adders. composition chips allows us to “grow” this size without needing to re-prove correctness. We only need to prove composition is correct. All of this also holds for our eventual multiplication design. which is build from an adder and composition of other multiplication chips. We shall see that proving correctness of composition isn’t easy. Once done, all compositions will provably correct however. &lt;a href=&quot;#fn8&quot; class=&quot;footnote-ref&quot; id=&quot;fnref8&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;8&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A concrete example of &lt;code&gt;μ&lt;/code&gt; would be an interpertation into binary values:&lt;/p&gt;
&lt;p&gt;If we put this into the Adder then &lt;code&gt;τ = Bool&lt;/code&gt;. &lt;code&gt;interpretBF&lt;/code&gt; in this case interprets our code as a boolean value in natural numbers. In other words the homomorphism. This says what value a true and a false are in natural numbers. Now can define how to add bits:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;#cb3-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;add2 &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; Adder interpretBF &lt;span class=&quot;co&quot;&gt;-- 1&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;#cb3-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;add add2 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;zero , false , false&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;     &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; false , zero &lt;span class=&quot;co&quot;&gt;-- 2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;#cb3-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-5&quot;&gt;&lt;a href=&quot;#cb3-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;add add2 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc zero , true , true&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; true  , suc zero&lt;/span&gt;
&lt;span id=&quot;cb3-6&quot;&gt;&lt;a href=&quot;#cb3-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zeroA add2 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; false &lt;span class=&quot;co&quot;&gt;-- 3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we first define the type of &lt;code&gt;add2&lt;/code&gt; at &lt;code&gt;1&lt;/code&gt;. This uses the previously defined &lt;code&gt;interpretBF&lt;/code&gt; to set &lt;code&gt;τ = Bool&lt;/code&gt;. Then we start giving an implementation for &lt;code&gt;add&lt;/code&gt; at &lt;code&gt;2&lt;/code&gt;, which is a simple pattern match into values. finally we give an implementation of &lt;code&gt;zeroA&lt;/code&gt; at &lt;code&gt;3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can do a quick correctness check before doing a full prove. For example, in multiplication we didn’t do the full on homorphism prove at first. It looked daunting, so we settled on making a &lt;a href=&quot;https://github.com/isovector/denotational-arithmetic-zurihac/commit/4eb494ad84a1ede2202b036379d8525a391eecbb#diff-201315dac0498e664f0dccffd803e509020bf7d50ce3509d27566a3c26e5cb38R273&quot;&gt;unit test&lt;/a&gt; instead. If we map out all possible inputs to all possible outputs we got a crummy proof:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;#cb4-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;V&lt;span class=&quot;ot&quot;&gt;.&lt;/span&gt;map &lt;span class=&quot;co&quot;&gt;-- 1&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;#cb4-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;toℕ ∘ pairμ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;pairμ interpretBF&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ∘ uncurry &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;mult mul2x2&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; $ &lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;#cb4-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        composeTheValues allBools2x2 allBools2x2&lt;/span&gt;
&lt;span id=&quot;cb4-4&quot;&gt;&lt;a href=&quot;#cb4-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-5&quot;&gt;&lt;a href=&quot;#cb4-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ∷ &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ∷ &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ∷ &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ∷  &lt;span class=&quot;co&quot;&gt;-- 2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-6&quot;&gt;&lt;a href=&quot;#cb4-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ∷ &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; ∷ &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; ∷ &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; ∷&lt;/span&gt;
&lt;span id=&quot;cb4-7&quot;&gt;&lt;a href=&quot;#cb4-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ∷ &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; ∷ &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt; ∷ &lt;span class=&quot;dv&quot;&gt;6&lt;/span&gt; ∷&lt;/span&gt;
&lt;span id=&quot;cb4-8&quot;&gt;&lt;a href=&quot;#cb4-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ∷ &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; ∷ &lt;span class=&quot;dv&quot;&gt;6&lt;/span&gt; ∷ &lt;span class=&quot;dv&quot;&gt;9&lt;/span&gt; ∷ []&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-9&quot;&gt;&lt;a href=&quot;#cb4-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At &lt;code&gt;1&lt;/code&gt; we put our chip design into the interpretation, and at &lt;code&gt;2&lt;/code&gt; we expect a multiplication table as result. Is this test complete? No, this only works for binary values up to 9, we’ve not tested for trits or pentits or higher values. We did prove however the chip behaves like we expect for these values. If you’re building a chip company where you only need multiplication up to 9 in base 2 this is good enough. As far unit tests go this is incredibly thorough because we’re testing against all possible values in the chip design. The more common approach is to sample a couple values and call it a day.&lt;/p&gt;
&lt;p&gt;Which lead to an alternative approach called property testing. Here you would generate two random inputs on one side, interpret it trough the homomorphism and then see if the multiplication in natural numbers is the same as the test. We didn’t do this because it’s sort of difficult to do in Agda.&lt;a href=&quot;#fn9&quot; class=&quot;footnote-ref&quot; id=&quot;fnref9&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;9&lt;/sup&gt;&lt;/a&gt; Now you need to figure out how to get your source of randomness. Also time was a serious constraint, and we had a more powerful and interesting technique, proving! A proof doesn’t have to be hard, for example consider the correctness prove for our add2 chip:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  proof-add add2 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;zero , false , false&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;#cb5-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-3&quot;&gt;&lt;a href=&quot;#cb5-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  proof-add add2 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc zero , true  , true&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;refl&lt;/code&gt; means, &lt;a href=&quot;https://en.wikipedia.org/wiki/Reflexive_relation&quot;&gt;reflexivity&lt;/a&gt;. In other words, the statement is simple enough that Agda can just look at the definition to figure out what it means. In this case all we do is list out all possible input values, and tell agda to look at the definition. &lt;code&gt;proof-add&lt;/code&gt;’s type signature ensures the implementation is correct. This is only possible because Agda is dependently typed. What we proved is that the homorphism is the same under composition for the addition.&lt;/p&gt;
&lt;p&gt;This will work for the add2 chip. However the add2 chip is kindoff useless by itself since it can only add 2 bits. Our idea was to compose these adders into bigger adders so that any size can be represented. To do this we first define the type signature:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;#cb6-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;bigger-adder &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;σ τ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;σ-size τ-size &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;μ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; σ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Fin σ-size&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;ν &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; τ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Fin τ-size&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;#cb6-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Adder μ &lt;span class=&quot;co&quot;&gt;-- 1&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;#cb6-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Adder ν &lt;span class=&quot;co&quot;&gt;-- 2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;#cb6-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Adder &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;uncurry combine ∘ P&lt;span class=&quot;ot&quot;&gt;.&lt;/span&gt;map μ ν&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- 3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we’re putting in a low adder &lt;code&gt;1&lt;/code&gt;, a high adder &lt;code&gt;2&lt;/code&gt; which results into a combined adder &lt;code&gt;3&lt;/code&gt;. &lt;code&gt;μ&lt;/code&gt; and &lt;code&gt;ν&lt;/code&gt; are placeholders for different adders. This allows us to for example add trits to bits. The resulting adder &lt;code&gt;3&lt;/code&gt; maps over both sides of the resulting tuple&lt;a href=&quot;#fn10&quot; class=&quot;footnote-ref&quot; id=&quot;fnref10&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;10&lt;/sup&gt;&lt;/a&gt; with the interpertation.&lt;/p&gt;
&lt;p&gt;If you squint a little, the implementation looks like a circuit:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;#cb7-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;add &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;bigger-adder x y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- 1&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;#cb7-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;cin , &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;mhi , mlo&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;nhi , nlo&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- 2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;#cb7-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- 3&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;#cb7-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;lo , cmid&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; y &lt;span class=&quot;ot&quot;&gt;.&lt;/span&gt;add $ cin , mlo , nlo &lt;/span&gt;
&lt;span id=&quot;cb7-5&quot;&gt;&lt;a href=&quot;#cb7-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;hi , cout&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;.&lt;/span&gt;add $ cmid , mhi , nhi&lt;/span&gt;
&lt;span id=&quot;cb7-6&quot;&gt;&lt;a href=&quot;#cb7-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;hi , lo&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , cout&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- 4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At &lt;code&gt;1&lt;/code&gt; we’re copattern matching on bigger-adder so we can get the underlying &lt;code&gt;μ&lt;/code&gt; and &lt;code&gt;ν&lt;/code&gt; adders as &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; respectively. At &lt;code&gt;2&lt;/code&gt; we’re getting the actual arguments into the bigger adder. The type of this is $ Fin _2 () ()$ this is where the carry comes into play as argument since an adder needs to be able to tell when it overflows &lt;a href=&quot;#fn11&quot; class=&quot;footnote-ref&quot; id=&quot;fnref11&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;11&lt;/sup&gt;&lt;/a&gt;. The actual addition in &lt;code&gt;3&lt;/code&gt; we pawn off to the underlying adders &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;, all we do is hook in the carry&lt;a href=&quot;#fn12&quot; class=&quot;footnote-ref&quot; id=&quot;fnref12&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;12&lt;/sup&gt;&lt;/a&gt;. In &lt;code&gt;4&lt;/code&gt; we emit the results.&lt;/p&gt;
&lt;p&gt;Once we were reasonably confident of our implementation, we want to prove this correctness. This is a bit more involved than proving the boolean interpretation:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;#cb8-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;proof-add &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;bigger-adder &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;σ-size &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; σ-size&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;τ-size &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; τ-size&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;μ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; μ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;ν &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ν&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; x y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;#cb8-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;cin , &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;mhi , mlo&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;nhi , nlo&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;#cb8-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; y &lt;span class=&quot;ot&quot;&gt;.&lt;/span&gt;add &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;cin , mlo , nlo&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt; y-eq&lt;/span&gt;
&lt;span id=&quot;cb8-4&quot;&gt;&lt;a href=&quot;#cb8-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;lo , cmid&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;.&lt;/span&gt;add &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;cmid , mhi , nhi&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt; x-eq&lt;/span&gt;
&lt;span id=&quot;cb8-5&quot;&gt;&lt;a href=&quot;#cb8-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;hi , cout&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-6&quot;&gt;&lt;a href=&quot;#cb8-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; x-proof &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; proof-add x &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;cmid , mhi , nhi&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- 3&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-7&quot;&gt;&lt;a href=&quot;#cb8-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      y-proof &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; proof-add y &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;cin  , mlo , nlo&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-8&quot;&gt;&lt;a href=&quot;#cb8-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      size &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; σ-size&lt;/span&gt;
&lt;span id=&quot;cb8-9&quot;&gt;&lt;a href=&quot;#cb8-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt; begin&lt;/span&gt;
&lt;span id=&quot;cb8-10&quot;&gt;&lt;a href=&quot;#cb8-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  begin&lt;/span&gt;
&lt;span id=&quot;cb8-11&quot;&gt;&lt;a href=&quot;#cb8-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    toℕ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;cast &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;combine cout &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;combine &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ hi&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ lo&lt;span class=&quot;ot&quot;&gt;))))&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- 1&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-12&quot;&gt;&lt;a href=&quot;#cb8-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ≡⟨ toℕ-cast &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;combine cout &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;combine &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ hi&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ lo&lt;span class=&quot;ot&quot;&gt;)))&lt;/span&gt; ⟩&lt;/span&gt;
&lt;span id=&quot;cb8-13&quot;&gt;&lt;a href=&quot;#cb8-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    toℕ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;combine cout &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;combine &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ hi&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ lo&lt;span class=&quot;ot&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-14&quot;&gt;&lt;a href=&quot;#cb8-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ≡⟨ toℕ-combine cout &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩&lt;/span&gt;
&lt;span id=&quot;cb8-15&quot;&gt;&lt;a href=&quot;#cb8-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    size * size * toℕ cout + toℕ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;combine &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ hi&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ lo&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-16&quot;&gt;&lt;a href=&quot;#cb8-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ≡⟨ cong &lt;span class=&quot;ot&quot;&gt;(\&lt;/span&gt; φ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; size * size * toℕ cout + φ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;toℕ-combine &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ hi&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ lo&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; ⟩&lt;/span&gt;
&lt;span id=&quot;cb8-17&quot;&gt;&lt;a href=&quot;#cb8-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    size * size * toℕ cout + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;size * toℕ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ hi&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; + toℕ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ lo&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-18&quot;&gt;&lt;a href=&quot;#cb8-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ≡⟨ &lt;span class=&quot;ot&quot;&gt;{! taneb !}&lt;/span&gt; ⟩&lt;/span&gt;
&lt;span id=&quot;cb8-19&quot;&gt;&lt;a href=&quot;#cb8-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    toℕ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;addF&amp;#39; cin &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;combine &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ mhi&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ mlo&lt;span class=&quot;ot&quot;&gt;)))&lt;/span&gt; + toℕ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;combine &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ nhi&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ nlo&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-20&quot;&gt;&lt;a href=&quot;#cb8-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ≡⟨ sym $ toℕ-addF&amp;#39; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;addF&amp;#39; cin &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;combine &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ mhi&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ mlo&lt;span class=&quot;ot&quot;&gt;)))&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;combine &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ nhi&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ nlo&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; ⟩&lt;/span&gt;
&lt;span id=&quot;cb8-21&quot;&gt;&lt;a href=&quot;#cb8-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    toℕ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;addF&amp;#39; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;addF&amp;#39; cin &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;combine &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ mhi&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ mlo&lt;span class=&quot;ot&quot;&gt;)))&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;combine &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ nhi&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;μ nlo&lt;span class=&quot;ot&quot;&gt;)))&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- 2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-22&quot;&gt;&lt;a href=&quot;#cb8-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ∎&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note I drastically shortened this proof to make it fit &lt;a href=&quot;#fn13&quot; class=&quot;footnote-ref&quot; id=&quot;fnref13&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;13&lt;/sup&gt;&lt;/a&gt;. What do is making the first line (indicated by &lt;code&gt;1&lt;/code&gt;) be the same as the last line (indicated by &lt;code&gt;2&lt;/code&gt;) through steps with equational reasoning. Every step is small, and the process is almost fully mechanical pattern matching. A step is anything within &lt;code&gt;≡⟨ ⟩&lt;/code&gt;, which does some small syntax transformation. The &lt;code&gt;≡⟨ {! taneb !} ⟩&lt;/code&gt; is a missing step, called a hole. In this case we request taneb&lt;a href=&quot;#fn14&quot; class=&quot;footnote-ref&quot; id=&quot;fnref14&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;14&lt;/sup&gt;&lt;/a&gt;, to figure out what goes here. In &lt;code&gt;3&lt;/code&gt;, we’re summoning the proofs from the &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; adders to use in the proof later. We’re making a bigger proof out of smaller ones.&lt;/p&gt;
&lt;p&gt;If this proof is incorrect, you’ll get a compile error.&lt;a href=&quot;#fn15&quot; class=&quot;footnote-ref&quot; id=&quot;fnref15&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;15&lt;/sup&gt;&lt;/a&gt; This is similar to property tests, although it doesn’t use randomness and shrinking, but rather the structure of the implementation through dependent types. This is a big step up in terms off correctness compared to property tests. No longer can you have stochastic issues like insufficient sampling, or biased distributions. Furthermore smaller proofs compose into larger ones (with the right design). We can see that for example with &lt;code&gt;x-proof&lt;/code&gt; in the above block. Not just that, but every step between &lt;code&gt;≡⟨ ⟩&lt;/code&gt; is a prove being re-used. Property tests however aren’t as composable as proofs. A value generator may be re-used, however care must be taken the sampling and bias doesn’t become unacceptable. Finally we’re able to prove on polymorphic type variables, which property tests can’t do. If you have software that /needs/ to be correct, I think this dependently typed prove approach is a very good option to consider. I also think Agda is an good choice for a language that supports that.&lt;/p&gt;
&lt;h2 id=&quot;parting-words&quot;&gt;Parting words&lt;/h2&gt;
&lt;p&gt;Denotational design is an excellent topic of study if you’re struggling with questions like “how do I make my code be more pretty?”, or “how do I design nice and easy to understand libraries?”. Furthermore, even for commercial code bases we can have correctness proofs. This is a much more powerful technique than mere property tests, and puts all that hype around dependent types to work. We don’t need to rely on hand wavy laws asserted merely by stochastic approximations of proofs, we can do the real deal! Please reach out if you’re in a domain where correctness like this is important. I’d love to chat :).&lt;/p&gt;
&lt;p&gt;Finally I especially want to thank to both Nathan and Sandy for giving useful feedback on my humble writings. I also wish thank all other volunteers who participated, I had a great time.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;As the name implies. This place is 30 minutes or so driving from Zurich.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;I’m on the left.&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;As the name implies. This place is 30 minutes or so driving from Zurich.&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;In a commercial setting we’d decide if it’s worth investing additional in this design. The one presented at Zurich hack works. But if this is intended to be used in a larger system, iterating upon the design may help, if the business can afford it.&lt;a href=&quot;#fnref4&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn5&quot;&gt;&lt;p&gt;Addition chip&lt;a href=&quot;#fnref5&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn6&quot;&gt;&lt;p&gt;In zurich hack we sortoff started out in a classroom with just random ideas. One was quite funny where we somehow ended up with a design that was equivalent to tallying the ones and zeros. But we went in all kinds of directions before settling on using a record. I guess that’s the point you’ve to just try a bunch of stuff and not put to much ego into it.&lt;a href=&quot;#fnref6&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn7&quot;&gt;&lt;p&gt;When I asked Nathan to review this post, he mentioned he still hasn’t figured out why we needed a zero. I’m not really sure either, so it’s quite likely this isn’t needed at all! This maybe an artifact of the time crunch at play.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;interpretBF &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; Bool &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Fin &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;interpretBF false &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; zero&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;#cb2-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;interpretBF true  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc zero&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;a href=&quot;#fnref7&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn8&quot;&gt;&lt;p&gt;Unfortunately during the hackaton we didn’t finish this for multiplication, but we did for addition.&lt;a href=&quot;#fnref8&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn9&quot;&gt;&lt;p&gt;For me that is, because rember, I’m quite new to this all.&lt;a href=&quot;#fnref9&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn10&quot;&gt;&lt;p&gt;P stands for product in this case. So it’s a bimap over a tuple (due to uncurry).&lt;a href=&quot;#fnref10&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn11&quot;&gt;&lt;p&gt;As I mentioned in the design section, I don’t believe this is necessary, but this is an open research question.&lt;a href=&quot;#fnref11&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn12&quot;&gt;&lt;p&gt;Someone may or may not have opened &lt;a href=&quot;https://nandgame.com/&quot;&gt;nandgame&lt;/a&gt; during zurich hack to show a schema off an adder when we were struggling with correctness.&lt;a href=&quot;#fnref12&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn13&quot;&gt;&lt;p&gt;The full proof can be seen in the &lt;a href=&quot;https://github.com/isovector/denotational-arithmetic-zurihac&quot;&gt;github repository&lt;/a&gt;, although we made some additional changes to the project after the presentation as well.&lt;a href=&quot;#fnref13&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn14&quot;&gt;&lt;p&gt;Nathan, a magical ring solver, or flesh and blood person, whichever interpretation suits you better.&lt;a href=&quot;#fnref14&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn15&quot;&gt;&lt;p&gt;So what if you’re stuck on a proof? This either means you can’t think of a function, or it means the thing you’re trying to do is impossible. Here you’d need to think really hard if the thing you’re designing is correct. You could also try to discuss the issue with a friend or ask on &lt;a href=&quot;https://wiki.portal.chalmers.se/agda/Main/Community&quot;&gt;the internet&lt;/a&gt;. Plenty of people eager to help.&lt;a href=&quot;#fnref15&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Restoring mysql innodb on windows.</title>
    <link href="https://jappieklooster.nl/restoring-mysql-innodb-on-windows.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2022-06-16:/restoring-mysql-innodb-on-windows.html</id>
    <published>2022-06-16T22:30:00Z</published>
    <updated>2023-01-17T17:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;Over the weekend a company had a power outage, causing corruption to the on premise hosted mysql innodb database. This means the company can’t do any work, so I had to fix this fast before they opened again on Monday. It’s not trivial because the system runs on windows, which&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Over the weekend a company had a power outage, causing corruption to the on premise hosted mysql innodb database. This means the company can’t do any work, so I had to fix this fast before they opened again on Monday. It’s not trivial because the system runs on windows, which means the online guides don’t quite work. Therefore I wrote these notes for future me.&lt;/p&gt;
&lt;p&gt;We can boot the database with &lt;a href=&quot;https://dev.mysql.com/doc/refman/5.6/en/forcing-innodb-recovery.html&quot;&gt;force recovery&lt;/a&gt; In my case I had to set it to 3, try as low as possible. It puts everything in read only but that’s good enough. The recovery is a process of exporting these read only databases to sql, creating an entire new instalation with a new datafolder, and reading these back into that. The linux instruction can be found &lt;a href=&quot;https://dba.stackexchange.com/questions/65728/forcing-innodb-recovery-of-a-corrupted-database&quot;&gt;here&lt;/a&gt;. This post is specifically about windows. We need to run from cmd not powershell, powershell doesn’t understand &lt;code&gt;&amp;lt;&lt;/code&gt;, and I’ve doubts about it understanding &lt;code&gt;&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To get a working installation I set &lt;code&gt;innod_force_recovery = 3&lt;/code&gt; in &lt;code&gt;mysql\bin\my.ini&lt;/code&gt;, which can be found in xampp. First we have to restart mysql so we can get the data out. Now we can dump the tables:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode cmd&quot;&gt;&lt;code class=&quot;sourceCode dosbat&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;./mysqldump.exe &lt;span class=&quot;at&quot;&gt;-u&lt;/span&gt; root &lt;span class=&quot;at&quot;&gt;-pwhatever&lt;/span&gt; -&lt;span class=&quot;at&quot;&gt;-skip-lock-tables&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-A&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;&amp;gt;&lt;/span&gt; all.sql&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And shut down the server.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode cmd&quot;&gt;&lt;code class=&quot;sourceCode dosbat&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;./mysqladmin &lt;span class=&quot;at&quot;&gt;-u&lt;/span&gt; root &lt;span class=&quot;at&quot;&gt;-pwhatever&lt;/span&gt; shut&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I just emptied the datafolder with explorer, by navigating to &lt;code&gt;T:/xampp/mysql/data&lt;/code&gt;, and deleting everything in there. Now I ran:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;./mysql_istall_db.exe&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;--datadir&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;T:\xampp\mysql\data&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I set &lt;code&gt;innod_force_recovery&lt;/code&gt; to a comment again and restart mysql from xampp, I also checked if it ran in process monitor.&lt;/p&gt;
&lt;p&gt;set the root password correctly again:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;#cb4-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;mysql&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-u&lt;/span&gt; root&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;#cb4-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;SET&lt;/span&gt; PASSWORD FOR &lt;span class=&quot;st&quot;&gt;&amp;#39;root&amp;#39;&lt;/span&gt;@&lt;span class=&quot;st&quot;&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt; = PASSWORD&lt;span class=&quot;er&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;#39;whatever&amp;#39;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;#cb4-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;FLUSH&lt;/span&gt; PRIVILEGES&lt;span class=&quot;kw&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;restore:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;mysql&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-u&lt;/span&gt; root &lt;span class=&quot;at&quot;&gt;-pwhatever&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt; all.sql&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Failing in Haskell</title>
    <link href="https://jappieklooster.nl/failing-in-haskell.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2022-02-27:/failing-in-haskell.html</id>
    <published>2022-02-27T00:00:00Z</published>
    <updated>2022-03-05T03:40:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="technique"/>
    <summary type="html">&lt;figure&gt;
&lt;img src=&quot;images/2022/failure.png&quot; alt=&quot;I’m a Haskell failure, don’t tell anyone!&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;I’m a Haskell failure, don’t tell anyone!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Recently I encountered some dubious error handling code. Not only was it failing, it was failing WRONG &lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;. This frustrates me because doing failing correctly in Haskell is quite easy, so why was it implemented wrongly? I believe no-one has addressed failing&lt;/p&gt;</summary>
    <content type="html">&lt;figure&gt;
&lt;img src=&quot;images/2022/failure.png&quot; alt=&quot;I’m a Haskell failure, don’t tell anyone!&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;I’m a Haskell failure, don’t tell anyone!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Recently I encountered some dubious error handling code. Not only was it failing, it was failing WRONG &lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;. This frustrates me because doing failing correctly in Haskell is quite easy, so why was it implemented wrongly? I believe no-one has addressed failing with an opinion. Plenty of people describe the &lt;a href=&quot;http://www.randomhacks.net/2007/03/10/haskell-8-ways-to-report-errors/&quot;&gt;various&lt;/a&gt; &lt;a href=&quot;https://www.stackbuilders.com/blog/errors-and-exceptions-in-haskell/&quot;&gt;ways&lt;/a&gt; &lt;a href=&quot;https://www.fpcomplete.com/haskell/tutorial/exceptions/&quot;&gt;you&lt;/a&gt; &lt;a href=&quot;https://www.schoolofhaskell.com/school/starting-with-haskell/basics-of-haskell/10_Error_Handling&quot;&gt;can&lt;/a&gt; &lt;a href=&quot;https://wiki.haskell.org/Handling_errors_in_Haskell&quot;&gt;fail&lt;/a&gt;. But none give opinions on why certain ways are better than others. Therefore I shall share my failing expertise, and describe the correct way to fail in Haskell. In essence, this is an answer to Eric Kidd’s &lt;a href=&quot;http://www.randomhacks.net/2007/03/10/haskell-8-ways-to-report-errors/&quot;&gt;plea for consistency&lt;/a&gt; &lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;. These are the properties we want from failure:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;Preciseness, vague errors are bad.&lt;/li&gt;
&lt;li&gt;Locality, we need to know where errors come from.&lt;/li&gt;
&lt;li&gt;Recoverability, the program should be able to recover after an error.&lt;/li&gt;
&lt;li&gt;Change ability, introduction of new error cases should be easy.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We want all these properties to make debugging easier. This allows you to solve complicated bugs within minutes. We structure the program so that it tells what goes wrong, where and why. This isn’t magic. It takes effort, but not magic at all.&lt;/p&gt;
&lt;p&gt;I’ll describe how to achieve the above properties with some example code for both pure and side effectful code. However these principles apply to other languages as well &lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;. We’ll also go over some anti patterns and discuss their mediation.&lt;/p&gt;
&lt;h1 id=&quot;pure&quot;&gt;Pure&lt;/h1&gt;
&lt;p&gt;Haskell programmers prefer so called ‘pure’ code. By which we mean immutable memory computations&lt;a href=&quot;#fn4&quot; class=&quot;footnote-ref&quot; id=&quot;fnref4&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt;. Therefore we start with the pure case. Ideally pure code fail management looks like this:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LookupError&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NotFound&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;lookup&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LookupError&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;lookup&lt;/span&gt; env argA &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;maybe&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;NotFound&lt;/span&gt; argA)) &lt;span class=&quot;dt&quot;&gt;Right&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; Map.lookup argA env&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;#cb1-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;#cb1-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivideErrors&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivideLookup&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LookupError&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;#cb1-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivisionByZero&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;#cb1-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivNegativeDivision&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;#cb1-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivNumberThreeIsBad&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-10&quot;&gt;&lt;a href=&quot;#cb1-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-11&quot;&gt;&lt;a href=&quot;#cb1-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;divide ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivideErrors&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-12&quot;&gt;&lt;a href=&quot;#cb1-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divide env argA argB &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-13&quot;&gt;&lt;a href=&quot;#cb1-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    valA &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; first &lt;span class=&quot;dt&quot;&gt;DivideLookup&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;lookup&lt;/span&gt; env argA&lt;/span&gt;
&lt;span id=&quot;cb1-14&quot;&gt;&lt;a href=&quot;#cb1-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    valB &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; first &lt;span class=&quot;dt&quot;&gt;DivideLookup&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;lookup&lt;/span&gt; env argB&lt;/span&gt;
&lt;span id=&quot;cb1-15&quot;&gt;&lt;a href=&quot;#cb1-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    when (valB &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivisionByZero&lt;/span&gt; valA valB&lt;/span&gt;
&lt;span id=&quot;cb1-16&quot;&gt;&lt;a href=&quot;#cb1-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    when (valB &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivNegativeDivision&lt;/span&gt; valA valB&lt;/span&gt;
&lt;span id=&quot;cb1-17&quot;&gt;&lt;a href=&quot;#cb1-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    when (valA &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;fl&quot;&gt;3.0&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;||&lt;/span&gt; valB &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;fl&quot;&gt;3.0&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivNumberThreeIsBad&lt;/span&gt; valA valB&lt;/span&gt;
&lt;span id=&quot;cb1-18&quot;&gt;&lt;a href=&quot;#cb1-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; valA &lt;span class=&quot;op&quot;&gt;/&lt;/span&gt; valB&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we introduce the divide function. Which takes an environment map, looks up the values of said map, and then performs division after doing some checks. We introduce the environment as a convenient common “this can fail” lookup. But business may give us other in-variants such as &lt;code&gt;DivNumberThreeIsBad&lt;/code&gt;, which also neatly fits in this “pattern”. Errors are emitted by using the &lt;code&gt;Left&lt;/code&gt; constructor, which is the error branch according to &lt;code&gt;Either&lt;/code&gt;’s &lt;code&gt;Monad&lt;/code&gt; instance.&lt;/p&gt;
&lt;p&gt;This code will tell you exactly what went wrong if something goes wrong. Locality in this case can be improved a little by adding a different constructor for each &lt;code&gt;lookup&lt;/code&gt; call, but in this case I’d argue locality is close enough. The developer has the opportunity to recover from these errors, a simple pattern match would suffice. Furthermore if business demands yet another weird constraint, such as &lt;code&gt;NumberFourIsBad&lt;/code&gt;, pattern matches at call sites will emit a &lt;a href=&quot;https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/using-warnings.html#ghc-flag--Wincomplete-patterns&quot;&gt;&lt;code&gt;-Wincomplete-patterns&lt;/code&gt;&lt;/a&gt; warning.&lt;/p&gt;
&lt;p&gt;If we need to compose these errors in a larger program we can simply wrap previous errors in a bigger sumtype, consider the following function &lt;code&gt;plusDiv&lt;/code&gt; which emulates &lt;code&gt;(a + b) / c&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PlusErrors&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PlusLookup&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LookupError&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PlusNoZeroResults&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;#cb2-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PlusNumberThreeIsBad&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;#cb2-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;#cb2-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;plus ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PlusErrors&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;#cb2-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;plus env argA argB &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;#cb2-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    valA &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; first &lt;span class=&quot;dt&quot;&gt;PlusLookup&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;lookup&lt;/span&gt; env argA&lt;/span&gt;
&lt;span id=&quot;cb2-8&quot;&gt;&lt;a href=&quot;#cb2-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    valB &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; first &lt;span class=&quot;dt&quot;&gt;PlusLookup&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;lookup&lt;/span&gt; env argB&lt;/span&gt;
&lt;span id=&quot;cb2-9&quot;&gt;&lt;a href=&quot;#cb2-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    when (valA &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;fl&quot;&gt;3.0&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;||&lt;/span&gt; valB &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;fl&quot;&gt;3.0&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-10&quot;&gt;&lt;a href=&quot;#cb2-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PlusNumberThreeIsBad&lt;/span&gt; valA valB&lt;/span&gt;
&lt;span id=&quot;cb2-11&quot;&gt;&lt;a href=&quot;#cb2-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; res &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; valA &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; valB&lt;/span&gt;
&lt;span id=&quot;cb2-12&quot;&gt;&lt;a href=&quot;#cb2-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    when (res &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PlusNoZeroResults&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-13&quot;&gt;&lt;a href=&quot;#cb2-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; valA &lt;span class=&quot;op&quot;&gt;/&lt;/span&gt; valB&lt;/span&gt;
&lt;span id=&quot;cb2-14&quot;&gt;&lt;a href=&quot;#cb2-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-15&quot;&gt;&lt;a href=&quot;#cb2-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PlusDivErrors&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PDPlusError&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PlusErrors&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-16&quot;&gt;&lt;a href=&quot;#cb2-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                   &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PDDivErrors&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivideErrors&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-17&quot;&gt;&lt;a href=&quot;#cb2-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                   &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PDLookup&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LookupError&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-18&quot;&gt;&lt;a href=&quot;#cb2-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-19&quot;&gt;&lt;a href=&quot;#cb2-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- | (a + b) / c&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-20&quot;&gt;&lt;a href=&quot;#cb2-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;plusDiv ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-21&quot;&gt;&lt;a href=&quot;#cb2-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-22&quot;&gt;&lt;a href=&quot;#cb2-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PlusDivErrors&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-23&quot;&gt;&lt;a href=&quot;#cb2-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;plusDiv env argA argB argC &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-24&quot;&gt;&lt;a href=&quot;#cb2-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  res &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; first &lt;span class=&quot;dt&quot;&gt;PDPlusError&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; plus env argA argB&lt;/span&gt;
&lt;span id=&quot;cb2-25&quot;&gt;&lt;a href=&quot;#cb2-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  cres &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; first &lt;span class=&quot;dt&quot;&gt;PDLookup&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;lookup&lt;/span&gt; env argC&lt;/span&gt;
&lt;span id=&quot;cb2-26&quot;&gt;&lt;a href=&quot;#cb2-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  first &lt;span class=&quot;dt&quot;&gt;PDDivErrors&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-27&quot;&gt;&lt;a href=&quot;#cb2-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    divide (Map.fromList [(&lt;span class=&quot;st&quot;&gt;&amp;quot;one&amp;quot;&lt;/span&gt;, res), (&lt;span class=&quot;st&quot;&gt;&amp;quot;two&amp;quot;&lt;/span&gt;, cres)]) &lt;span class=&quot;st&quot;&gt;&amp;quot;one&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;two&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The higher ‘level’ function &lt;code&gt;plusDiv&lt;/code&gt; absorbs all errors from other functions with extra constructors. This isn’t the most ergonomic approach because variables have to go through the environment map. In a real program you could factor out this function. For example with an &lt;code&gt;innerPlus :: Double -&amp;gt; Double -&amp;gt; Either PlusErrors Double&lt;/code&gt;. This adds additional type safety as well, because the &lt;code&gt;Double&lt;/code&gt; type is “smaller” then a &lt;code&gt;Text&lt;/code&gt; type in both memory and cardinality. However I think for an example or early prototype it’s good. Once more this tells us exactly what part of the computation failed, if any. In this case, the &lt;a href=&quot;https://hackage.haskell.org/package/bifunctors-5/docs/Data-Bifunctor.html#v:first&quot;&gt;first&lt;/a&gt; function is being used like &lt;a href=&quot;https://hackage.haskell.org/package/transformers-0.6.0.2/docs/Control-Monad-Trans-Class.html#v:lift&quot;&gt;lift&lt;/a&gt;: Transforming the function it wraps to run in the “higher level” &lt;code&gt;Either&lt;/code&gt; environment. Some may even call this a natural transformation.&lt;/p&gt;
&lt;p&gt;In certain cases you can use &lt;a href=&quot;https://hackage.haskell.org/package/validation-1.1.2/docs/Data-Validation.html&quot;&gt;Data.Validation&lt;/a&gt; instead of &lt;code&gt;Either&lt;/code&gt;. Which can collect more then one error. But usage of that is out of the scope of this blogpost.&lt;/p&gt;
&lt;h1 id=&quot;io-and-exceptions&quot;&gt;&lt;code&gt;IO&lt;/code&gt; and exceptions&lt;/h1&gt;
&lt;p&gt;It’s more difficult to recover from an exception than it is from a pure error value. As a rule of thumb you can use exceptions when you expect the program to stop. For example when you can’t find a critical resources from the database. Another consideration is the value of the error. If it’s important that an error be handled correctly, then exceptions should be avoided. However, this should only be done within a monad stack that has &lt;code&gt;IO&lt;/code&gt; as base, because exceptions are part of the &lt;code&gt;IO&lt;/code&gt; ‘contract’&lt;a href=&quot;#fn5&quot; class=&quot;footnote-ref&quot; id=&quot;fnref5&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt;. This contract extends to any transformer stack that has &lt;code&gt;IO&lt;/code&gt; as base. For convenience however, I’ll write out the example in plain &lt;code&gt;IO&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivideException&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;#cb3-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;MkDivideException&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasCallStack&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;#cb3-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;DivideErrors&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivideException&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;#cb3-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-5&quot;&gt;&lt;a href=&quot;#cb3-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivideException&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-6&quot;&gt;&lt;a href=&quot;#cb3-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-7&quot;&gt;&lt;a href=&quot;#cb3-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivideException&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-8&quot;&gt;&lt;a href=&quot;#cb3-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MkDivideException&lt;/span&gt; errors) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-9&quot;&gt;&lt;a href=&quot;#cb3-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        renderExceptionWithCallstack errors &lt;span class=&quot;st&quot;&gt;&amp;quot;MkDivideException&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-10&quot;&gt;&lt;a href=&quot;#cb3-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-11&quot;&gt;&lt;a href=&quot;#cb3-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;renderExceptionWithCallstack ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-12&quot;&gt;&lt;a href=&quot;#cb3-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        (&lt;span class=&quot;dt&quot;&gt;HasCallStack&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt; a) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-13&quot;&gt;&lt;a href=&quot;#cb3-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;renderExceptionWithCallstack errors valueConstructor &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;(&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; valueConstructor &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot; $ &amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-14&quot;&gt;&lt;a href=&quot;#cb3-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; errors&lt;/span&gt;
&lt;span id=&quot;cb3-15&quot;&gt;&lt;a href=&quot;#cb3-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;/*&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-16&quot;&gt;&lt;a href=&quot;#cb3-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; prettyCallStack callStack&lt;/span&gt;
&lt;span id=&quot;cb3-17&quot;&gt;&lt;a href=&quot;#cb3-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot; */)&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-18&quot;&gt;&lt;a href=&quot;#cb3-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-19&quot;&gt;&lt;a href=&quot;#cb3-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;throwDivide ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasCallStack&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivideErrors&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb3-20&quot;&gt;&lt;a href=&quot;#cb3-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;throwDivide &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;either&lt;/span&gt; (throwIO &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MkDivideException&lt;/span&gt;) &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-21&quot;&gt;&lt;a href=&quot;#cb3-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-22&quot;&gt;&lt;a href=&quot;#cb3-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;myEnv ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-23&quot;&gt;&lt;a href=&quot;#cb3-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;myEnv &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Map.fromList [(&lt;span class=&quot;st&quot;&gt;&amp;quot;zero&amp;quot;&lt;/span&gt;, &lt;span class=&quot;fl&quot;&gt;0.0&lt;/span&gt;), (&lt;span class=&quot;st&quot;&gt;&amp;quot;one&amp;quot;&lt;/span&gt;, &lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;fl&quot;&gt;1.0&lt;/span&gt;),&lt;/span&gt;
&lt;span id=&quot;cb3-24&quot;&gt;&lt;a href=&quot;#cb3-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                      (&lt;span class=&quot;st&quot;&gt;&amp;quot;two&amp;quot;&lt;/span&gt;, &lt;span class=&quot;fl&quot;&gt;2.0&lt;/span&gt;), (&lt;span class=&quot;st&quot;&gt;&amp;quot;three&amp;quot;&lt;/span&gt;, &lt;span class=&quot;fl&quot;&gt;3.0&lt;/span&gt;)]&lt;/span&gt;
&lt;span id=&quot;cb3-25&quot;&gt;&lt;a href=&quot;#cb3-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-26&quot;&gt;&lt;a href=&quot;#cb3-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;main ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb3-27&quot;&gt;&lt;a href=&quot;#cb3-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;main &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-28&quot;&gt;&lt;a href=&quot;#cb3-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    result1 &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; throwDivide &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; divide myEnv &lt;span class=&quot;st&quot;&gt;&amp;quot;one&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;two&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-29&quot;&gt;&lt;a href=&quot;#cb3-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    result2 &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; throwDivide &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; divide myEnv &lt;span class=&quot;st&quot;&gt;&amp;quot;one&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;three&amp;quot;&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- throws&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-30&quot;&gt;&lt;a href=&quot;#cb3-30&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; (result1 , result2)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All this boilerplate attaches the callstack to our exception. We also put the entire pure error type directly into the exception. It composes. This is why pure error handling is preferable, but if you don’t have time to do this, exceptions like those described above are good too. This idea of attaching call stacks to your exceptions is explained further in &lt;a href=&quot;https://maksbotan.github.io/posts/2021-01-20-callstacks.html&quot;&gt;this blogpost&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If that’s to much work, the &lt;a href=&quot;https://hackage.haskell.org/package/base/docs/Prelude.html#v:error&quot;&gt;&lt;code&gt;error&lt;/code&gt;&lt;/a&gt; call also has a stack trace, although its type allows vagueness unfortunately. Also make sure to attach it to IO, or the &lt;a href=&quot;#throw&quot;&gt;nullpointer&lt;/a&gt; anti pattern may occur. I think the &lt;a href=&quot;https://hackage.haskell.org/package/extra-1.7.10/docs/Control-Exception-Extra.html#v:errorIO&quot;&gt;&lt;code&gt;errorIO&lt;/code&gt;&lt;/a&gt; function is a good idea instead of &lt;code&gt;error&lt;/code&gt; because it avoids that nullpointer scenario entirely. Don’t try to catch errors, use exceptions if you need to catch.&lt;/p&gt;
&lt;h2 id=&quot;mtl&quot;&gt;MTL&lt;/h2&gt;
&lt;p&gt;I recently blogged about &lt;a href=&quot;%7Bfilename%7D/mtl.md&quot;&gt;mtl&lt;/a&gt;, so I’ll briefly cover how to modify this code into mtl style as well:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;#cb4-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;throwDivide ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;HasCallStack&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;MonadIO&lt;/span&gt; m)  &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExceptT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivideFailures&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m a&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;#cb4-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;throwDivide meow &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;#cb4-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    res &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runExceptT meow&lt;/span&gt;
&lt;span id=&quot;cb4-4&quot;&gt;&lt;a href=&quot;#cb4-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; res &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb4-5&quot;&gt;&lt;a href=&quot;#cb4-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; err &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; liftIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; throwIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MkDivideException&lt;/span&gt; err&lt;/span&gt;
&lt;span id=&quot;cb4-6&quot;&gt;&lt;a href=&quot;#cb4-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Right&lt;/span&gt; res &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; res&lt;/span&gt;
&lt;span id=&quot;cb4-7&quot;&gt;&lt;a href=&quot;#cb4-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-8&quot;&gt;&lt;a href=&quot;#cb4-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;myDBFunc ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadError&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DivideFailures&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;MonadDB&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-9&quot;&gt;&lt;a href=&quot;#cb4-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;myDBFunc &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-10&quot;&gt;&lt;a href=&quot;#cb4-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    myEnv &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; getMyEnv&lt;/span&gt;
&lt;span id=&quot;cb4-11&quot;&gt;&lt;a href=&quot;#cb4-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    divide myEnv &lt;span class=&quot;st&quot;&gt;&amp;quot;one&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;two&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-12&quot;&gt;&lt;a href=&quot;#cb4-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-13&quot;&gt;&lt;a href=&quot;#cb4-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;main ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb4-14&quot;&gt;&lt;a href=&quot;#cb4-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;main &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb4-15&quot;&gt;&lt;a href=&quot;#cb4-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    result1 &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runDB &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; throwDivide &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; myDBFunc &lt;/span&gt;
&lt;span id=&quot;cb4-16&quot;&gt;&lt;a href=&quot;#cb4-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; result1 &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;throwDivide&lt;/code&gt; works quite similarly as in the previous example but now it works with any transformer stack based on &lt;code&gt;IO&lt;/code&gt;. This works because we pretend the &lt;code&gt;ExceptT&lt;/code&gt; exists at the call site, which makes it come true. This is explained thoroughly in the previous &lt;a href=&quot;%7Bfilename%7D/mtl.md&quot;&gt;blog post&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;anti-patterns&quot;&gt;Anti patterns&lt;/h1&gt;
&lt;p&gt;Now I’ll cover several anti patterns I’ve seen and discuss what to do differently. Some of these patterns occur in the wild, for example &lt;a href=&quot;https://hackage.haskell.org/package/aeson-2.0.3.0/docs/Data-Aeson.html#v:eitherDecode&quot;&gt;aeson&lt;/a&gt; famously exposes a &lt;code&gt;String&lt;/code&gt; for errors, which is problematic for a library. The next section explains why.&lt;/p&gt;
&lt;h2 id=&quot;text-in-left-branch-of-either&quot;&gt;Text in left branch of Either&lt;/h2&gt;
&lt;p&gt;These examples contain text in the left branch:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;y ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;#cb5-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;x ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The problem is that we break the recoverability property. There is no way to make a closed pattern match on a string. Instead we should create a sumtype for possible errors:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;#cb6-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;YErrors&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;YErrorOne&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;#cb6-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;             &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;YErrorTwo&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;#cb6-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;#cb6-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;y ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;YErrors&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This way client code can pattern match on all possible branches, and if the additional errors get introduced the compiler notifies the developer through &lt;a href=&quot;https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/using-warnings.html#ghc-flag--Wincomplete-patterns&quot;&gt;&lt;code&gt;-Wincomplete-patterns&lt;/code&gt; warning&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;throw&quot;&gt;&lt;code&gt;throw&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;throw&lt;/code&gt; allows throwing exceptions in pure code. This is very wrong because the code ends up behaving like a null pointer in Java, due to Haskell’s non strict evaluation. In other words, this breaks the locality of errors. Consider for example:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;#cb7-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;myInts ::&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;#cb7-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;myInts &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;#cb7-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;#cb7-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EmptyException&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MkEmptyException&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-5&quot;&gt;&lt;a href=&quot;#cb7-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Exception&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb7-6&quot;&gt;&lt;a href=&quot;#cb7-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-7&quot;&gt;&lt;a href=&quot;#cb7-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;myHead ::&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-8&quot;&gt;&lt;a href=&quot;#cb7-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;myHead [] &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; throw &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MkEmptyException&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-9&quot;&gt;&lt;a href=&quot;#cb7-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;myHead (x &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; y) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb7-10&quot;&gt;&lt;a href=&quot;#cb7-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-11&quot;&gt;&lt;a href=&quot;#cb7-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;main ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb7-12&quot;&gt;&lt;a href=&quot;#cb7-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;main &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-13&quot;&gt;&lt;a href=&quot;#cb7-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; myHead myInts&lt;/span&gt;
&lt;span id=&quot;cb7-14&quot;&gt;&lt;a href=&quot;#cb7-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;] &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; myInts&lt;/span&gt;
&lt;span id=&quot;cb7-15&quot;&gt;&lt;a href=&quot;#cb7-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It fails on that last line. Even though the error was at the &lt;code&gt;x&lt;/code&gt; binding. Much better is to use &lt;a href=&quot;https://hackage.haskell.org/package/base/docs/Control-Exception.html#v:throwIO&quot;&gt;&lt;code&gt;throwIO&lt;/code&gt;&lt;/a&gt;, modifying the above example:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;#cb8-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;myInts ::&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;#cb8-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;myInts &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;#cb8-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-4&quot;&gt;&lt;a href=&quot;#cb8-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EmptyException&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MkEmptyException&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-5&quot;&gt;&lt;a href=&quot;#cb8-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Exception&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-6&quot;&gt;&lt;a href=&quot;#cb8-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-7&quot;&gt;&lt;a href=&quot;#cb8-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;myHead ::&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-8&quot;&gt;&lt;a href=&quot;#cb8-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;myHead [] &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; throwIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MkEmptyException&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-9&quot;&gt;&lt;a href=&quot;#cb8-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;myHead (x &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; y) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb8-10&quot;&gt;&lt;a href=&quot;#cb8-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-11&quot;&gt;&lt;a href=&quot;#cb8-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;main ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb8-12&quot;&gt;&lt;a href=&quot;#cb8-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;main &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-13&quot;&gt;&lt;a href=&quot;#cb8-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   x &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; myHead myInts&lt;/span&gt;
&lt;span id=&quot;cb8-14&quot;&gt;&lt;a href=&quot;#cb8-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;] &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; myInts&lt;/span&gt;
&lt;span id=&quot;cb8-15&quot;&gt;&lt;a href=&quot;#cb8-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will indeed fail on the first line. We lost purity, in this case &lt;code&gt;Either&lt;/code&gt; could have been used as described above, which is even better. Alternatively we can use the &lt;code&gt;HasCallStack&lt;/code&gt; trick, if we stick with exceptions.&lt;/p&gt;
&lt;h2 id=&quot;generic-app-exceptions&quot;&gt;Generic app exceptions&lt;/h2&gt;
&lt;p&gt;I’m talking about something like this:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;#cb9-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AppException&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MkAppException&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;#cb9-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Exception&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is bad because it ends up being thrown at many places with no good way of recovering. Exceptions are already difficult to recover from, but if they’re re-used a lot, it becomes even more difficult. Now you’d have to pattern match on the &lt;code&gt;Text&lt;/code&gt; to handle the correct error and hope no one re-uses that particular error text, ever! Furthermore the error may be vague, depending on what’s being put in the &lt;code&gt;Text&lt;/code&gt; field.&lt;/p&gt;
&lt;p&gt;It’s better to define a custom exception per situation. For example:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;#cb10-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DBUserNotFound&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MkDBUserNotFound&lt;/span&gt; {&lt;span class=&quot;ot&quot;&gt; userId ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UUID&lt;/span&gt; }&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;#cb10-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Exception&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;#cb10-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-4&quot;&gt;&lt;a href=&quot;#cb10-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AwsImgResourceNotFound&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MkImgResourceNotFound&lt;/span&gt; {&lt;span class=&quot;ot&quot;&gt;name ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt;,&lt;span class=&quot;ot&quot;&gt; awsId ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UUID&lt;/span&gt; }&lt;/span&gt;
&lt;span id=&quot;cb10-5&quot;&gt;&lt;a href=&quot;#cb10-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Exception&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These are precise and type safe, we no longer can be vague because you have to provide a &lt;code&gt;UUID&lt;/code&gt;. This forces the throw site to capture this &lt;code&gt;UUID&lt;/code&gt; from the environment, making the error precise trough type safety.&lt;/p&gt;
&lt;p&gt;However, you’ll likely already have generic app exception being called from different 400 places. Fortunately we can recover some of the locality property by rewriting the exception &lt;a href=&quot;https://maksbotan.github.io/posts/2021-01-20-callstacks.html#capturing-stacks&quot;&gt;in a GADT&lt;/a&gt; and using the &lt;code&gt;HasCallStack&lt;/code&gt; trick.&lt;/p&gt;
&lt;h2 id=&quot;squashing-errors&quot;&gt;Squashing errors&lt;/h2&gt;
&lt;p&gt;This can occur when using bind &lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt; on &lt;code&gt;Maybe&lt;/code&gt;, for example:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb11&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb11-1&quot;&gt;&lt;a href=&quot;#cb11-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;x ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-2&quot;&gt;&lt;a href=&quot;#cb11-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;y ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-3&quot;&gt;&lt;a href=&quot;#cb11-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-4&quot;&gt;&lt;a href=&quot;#cb11-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;z ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-5&quot;&gt;&lt;a href=&quot;#cb11-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-6&quot;&gt;&lt;a href=&quot;#cb11-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   x&amp;#39; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb11-7&quot;&gt;&lt;a href=&quot;#cb11-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   y&amp;#39; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; y&lt;/span&gt;
&lt;span id=&quot;cb11-8&quot;&gt;&lt;a href=&quot;#cb11-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; x&amp;#39; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; y&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Nothing&lt;/code&gt; won’t tell us why &lt;code&gt;z&lt;/code&gt; failed. This is wrong because it breaks preciseness. instead we should restructure like so:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;#cb12-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;x ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-2&quot;&gt;&lt;a href=&quot;#cb12-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;y ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-3&quot;&gt;&lt;a href=&quot;#cb12-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-4&quot;&gt;&lt;a href=&quot;#cb12-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ZFailures&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NoX&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-5&quot;&gt;&lt;a href=&quot;#cb12-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;               &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NoY&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-6&quot;&gt;&lt;a href=&quot;#cb12-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-7&quot;&gt;&lt;a href=&quot;#cb12-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;z ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ZFailures&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-8&quot;&gt;&lt;a href=&quot;#cb12-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-9&quot;&gt;&lt;a href=&quot;#cb12-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  x&amp;#39; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;maybe&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NoX&lt;/span&gt;) &lt;span class=&quot;dt&quot;&gt;Right&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb12-10&quot;&gt;&lt;a href=&quot;#cb12-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y&amp;#39; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;maybe&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NoY&lt;/span&gt;) &lt;span class=&quot;dt&quot;&gt;Right&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; y&lt;/span&gt;
&lt;span id=&quot;cb12-11&quot;&gt;&lt;a href=&quot;#cb12-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; x&amp;#39; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; y&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will tell you exactly what went wrong, while retaining most of the power of bind. It’s fine to use &lt;code&gt;Maybe&lt;/code&gt; if there is a single error case, but often this isn’t the case.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;The preference relation of failing is like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pure error handling &amp;gt; exceptions *with* stack traces &amp;gt; errorIO calls&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Anything else is most likely &lt;em&gt;wrong&lt;/em&gt; and should be avoided. Structure your programs so that it tells what goes wrong, where and why. I think most software would benefit from doing this, and these concepts are easy. Let &lt;a href=&quot;mailto:hi@jappie.me&quot;&gt;me know&lt;/a&gt; if you disagree, or need help with this.&lt;/p&gt;
&lt;h1 id=&quot;references&quot;&gt;References&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;https://github.com/waddlaw/haskell-stack-trace-plugin&lt;/li&gt;
&lt;li&gt;https://www.stackbuilders.com/blog/errors-and-exceptions-in-haskell/&lt;/li&gt;
&lt;li&gt;https://wiki.haskell.org/Handling_errors_in_Haskell&lt;/li&gt;
&lt;li&gt;http://www.randomhacks.net/2007/03/10/haskell-8-ways-to-report-errors/&lt;/li&gt;
&lt;li&gt;https://maksbotan.github.io/posts/2021-01-20-callstacks.html&lt;/li&gt;
&lt;li&gt;https://hackage.haskell.org/package/validation-1.1.2/docs/Data-Validation.html&lt;/li&gt;
&lt;li&gt;https://www.parsonsmatt.org/2018/11/03/trouble_with_typed_errors.html&lt;/li&gt;
&lt;/ul&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;Wrong as in they were following some of the ani patterns listed below.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;This is 15 years ago, ah well, better late then never I suppose.&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;When I was writing this I realized I do the exact same program structuring in Java or PHP. It is more work in Java or PHP, but possible and saves so much debugging time.&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;Accessing memory is for no particular reason considered pure, although one wonders if this could be changed to make managing memory bounds easier.&lt;a href=&quot;#fnref4&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn5&quot;&gt;&lt;p&gt;See the throw &lt;a href=&quot;#throw&quot;&gt;anti pattern&lt;/a&gt;&lt;a href=&quot;#fnref5&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Installing a NixOS desktop tracked with git</title>
    <link href="https://jappieklooster.nl/installing-a-nixos-desktop-tracked-with-git.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2022-01-30:/installing-a-nixos-desktop-tracked-with-git.html</id>
    <published>2022-01-30T16:20:00Z</published>
    <updated>2022-02-01T01:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;A few years ago I wrote a post on installing NixOS &lt;a href=&quot;%7Bfilename%7D/nixos-encrypted-btrfs.md&quot;&gt;on encrypted btrfs&lt;/a&gt;. I recently went trough that guide to install NixOS once more. It is good, but it has some issues:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;btrfs: Which I no longer use due to performance concerns.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/&quot;&gt;git&lt;/a&gt;: This requires some special&lt;/li&gt;&lt;/ol&gt;</summary>
    <content type="html">&lt;p&gt;A few years ago I wrote a post on installing NixOS &lt;a href=&quot;%7Bfilename%7D/nixos-encrypted-btrfs.md&quot;&gt;on encrypted btrfs&lt;/a&gt;. I recently went trough that guide to install NixOS once more. It is good, but it has some issues:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;btrfs: Which I no longer use due to performance concerns.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/&quot;&gt;git&lt;/a&gt;: This requires some special attention, but composes really well with nix and nixos.&lt;/li&gt;
&lt;li&gt;It doesn’t explain how to deal with secrets.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I’ll address these concerns here, since I &lt;em&gt;just&lt;/em&gt; bricked an install due to git usage &lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;. And I also wasted some time re-figuring out secrets.&lt;/p&gt;
&lt;p&gt;Why use git if it introduces complexity? For one it serves as an excellent backup tool, furthermore it allows managing multiple deployments side by side trough branches. Finally having a log of changes can be useful when things break. Things &lt;em&gt;will&lt;/em&gt; break. Such is the life of a tinkerer.&lt;/p&gt;
&lt;p&gt;I imagine some people still want to use btrfs, so I’ll leave the old guide in place. However, I’ll copy over parts which were good in here for convenience. This updated guide still uses encrypted disks, I’ve had no problems with this at all, and I recommend disk encryption to all.&lt;/p&gt;
&lt;h1 id=&quot;getting-started&quot;&gt;Getting started&lt;/h1&gt;
&lt;p&gt;Get yourself a NixOS &lt;a href=&quot;https://nixos.org/download.html#download-nixos&quot;&gt;live usb&lt;/a&gt;. I use the minimal ISO, because the graphical ISO slows booting and gives no advantage aside from being pretty. Use&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat minimal-nixos.iso &amp;gt; /dev/sdX&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where &lt;code&gt;X&lt;/code&gt; is the usb drive found by &lt;code&gt;lsblk&lt;/code&gt;. &lt;code&gt;X&lt;/code&gt; should be a letter, numbers indicate partitions, which we don’t want to cat upon because the ISO already contains a partitioning scheme.&lt;/p&gt;
&lt;p&gt;Boot into it on the target machine. Become root with &lt;code&gt;sudo -i&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&quot;internet&quot;&gt;Internet&lt;/h1&gt;
&lt;p&gt;Next step is to setup WIFI, you can skip this if you’re on Ethernet:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;wpa_passphrase&lt;/span&gt; SSID PASS &lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; /etc/wpa_supplicant.conf&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;systemctl&lt;/span&gt; restart wpa_supplicant&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first command creates a config for wpa_supplicant. The reader must fill in SSID and PASS of his target wifi network. The second command tells systemd to go restart wpa_supplicant and use the new config.&lt;/p&gt;
&lt;p&gt;Ask google if you’re online:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl google.com&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Should return a 301 Moved. If it hangs or refuses the connection you likely have no internet. There is no point proceeding until you have internet access.&lt;/p&gt;
&lt;h1 id=&quot;partitioning&quot;&gt;Partitioning&lt;/h1&gt;
&lt;p&gt;Now to setup the partitioning on the RIGHT device. Choose carefully. Use &lt;code&gt;lsblk&lt;/code&gt; to figure out which device is RIGHT. You’ll know it’s the WRONG device if you lose data after partitioning. The RIGHT device will be called &lt;code&gt;$dev&lt;/code&gt; hence forward.&lt;/p&gt;
&lt;p&gt;There are no other partitioning tools than gdisk. Only heretics believe there are. Therefore we use gdisk:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;#cb4-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;gdisk&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;$dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;gdisk-cheat-sheet&quot;&gt;Gdisk cheat sheet&lt;/h2&gt;
&lt;table&gt;
&lt;colgroup&gt;
&lt;col style=&quot;width: 11%&quot; /&gt;
&lt;col style=&quot;width: 88%&quot; /&gt;
&lt;/colgroup&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;For printing, to see what’s going on.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;For deletion, you should start out with deleting everything on &lt;code&gt;$dev&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;n&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Is used for creating new partitions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;w&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;is used for writing once finished.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This table just describes the commands needed for the intended partitioning.&lt;/p&gt;
&lt;h2 id=&quot;intended-partitioning&quot;&gt;Intended partitioning&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Number&lt;/th&gt;
&lt;th&gt;type&lt;/th&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;ef00&lt;/td&gt;
&lt;td&gt;+500M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;8200&lt;/td&gt;
&lt;td&gt;+$(SIZE_RAM+ a little)G&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;8300&lt;/td&gt;
&lt;td&gt;(rest of disk)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The first partition will be boot, the second swap[^optional], the third will be everything else. We will encrypt everything else. With type &lt;code&gt;ef00&lt;/code&gt; we will use UEFI for booting. Don’t worry. nix will handle that, mostly. Done. Onwards! [^optional]: This one is optional but allows hibernation. Which is very convenient for laptops. It can also make your system &lt;a href=&quot;https://askubuntu.com/questions/291378/do-we-still-need-swap-partitions-on-servers&quot;&gt;more stable&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;encryption&quot;&gt;Encryption&lt;/h1&gt;
&lt;p&gt;We use &lt;code&gt;cryptsetup&lt;/code&gt; for encryption. Make sure to select the right partition. We do not want to encrypt the boot partition because then we can’t boot. So if you followed above instructions it will be either &lt;code&gt;3&lt;/code&gt; or &lt;code&gt;p3&lt;/code&gt; (depending on device type). We’ll call it &lt;code&gt;3&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;cryptsetup&lt;/span&gt; luksFormat &lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dev&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;3&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;#cb5-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;cryptsetup&lt;/span&gt; open &lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dev&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;3 nixenc&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first command does the actual formatting, the second one opens up the formatted disk. You’ll need to provide the right password in both cases. Choose one you can remember but is strong. Once decrypted the disk will be mapped to &lt;code&gt;/dev/mapper/nixenc&lt;/code&gt;, note that we supplied that final part in the last command.&lt;/p&gt;
&lt;h1 id=&quot;formatting-filesystems&quot;&gt;Formatting filesystems&lt;/h1&gt;
&lt;p&gt;Partitioning is a distinct step from setting up filesystems.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;#cb6-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;mkfs.vfat&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-n&lt;/span&gt; boot &lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dev&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;1&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;#cb6-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;mkswap&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dev&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;2&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;#cb6-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;swapon&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dev&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;2&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;#cb6-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;mkfs.ext4&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-L&lt;/span&gt; root /dev/mapper/nixenc&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The boot partition will be &lt;code&gt;vfat&lt;/code&gt; because &lt;a href=&quot;https://wiki.archlinux.org/index.php/EFI_system_partition&quot;&gt;UEFI tells us to&lt;/a&gt;. The everything else partition will be &lt;code&gt;ext4&lt;/code&gt;. Note that we point it at the mapped file, if the &lt;code&gt;&quot;$dev&quot;3&lt;/code&gt;device were to be used directly we’d remove the encryption.&lt;/p&gt;
&lt;h1 id=&quot;mounting&quot;&gt;Mounting&lt;/h1&gt;
&lt;p&gt;Here we mount all partitions.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;#cb7-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;mount&lt;/span&gt; /dev/mapper/nixenc /mnt/&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;#cb7-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;mkdir&lt;/span&gt; /mnt/boot&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;#cb7-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;mount&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dev&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;1 /mnt/boot&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This makes them detectable by the nix config generation script. Furthermore it allows the script to write the config on the proper disk.&lt;/p&gt;
&lt;h2 id=&quot;did-i-do-everything-right&quot;&gt;Did I do everything right?&lt;/h2&gt;
&lt;p&gt;The second time I ran trough this post everything went quite quickly, so I became skeptical. To verify everything was sane I used the following commands:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;#cb8-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;mount&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;grep&lt;/span&gt; /mnt&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;#cb8-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;ls&lt;/span&gt; /mnt&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first command is to check if the encrypted volume and boot is mounted at the right paths. The second one to verify the folders are created.&lt;/p&gt;
&lt;h1 id=&quot;configure-nix-part-1-in-the-live-environment&quot;&gt;Configure nix part 1, in the live environment&lt;/h1&gt;
&lt;p&gt;We use a script to generate an intial nix configuration, which detects the hardware for us:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;#cb9-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;nixos-generate-config&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;--root&lt;/span&gt; /mnt&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will give us a default config which we can &lt;a href=&quot;https://nixos.org/nixos/manual/index.html#sec-changing-config&quot;&gt;customize&lt;/a&gt; now. You can also pick up ideas from &lt;a href=&quot;https://github.com/jappeace/linux-config/blob/work-machine/configuration.nix&quot;&gt;my config&lt;/a&gt;, although its a mess. On a wireless laptop, it’s highly recommended to enable &lt;a href=&quot;https://nixos.wiki/wiki/Wpa_supplicant&quot;&gt;wpa_supplicant&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode nix&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;#cb10-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;networking&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;wireless&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;enable = &lt;span class=&quot;cn&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Furthermore we’re going to need the packages vim and git to modify the config after booting into the system:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  environment = {
    systemPackages = [
        pkgs.git
        pkgs.vim
    ];
  };&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure to set the channel to the same as in your tracked git configuration, or alternatively be ready to deal with upgrades. For example on a live ISO of &lt;code&gt;21.11&lt;/code&gt; I downgraded to &lt;code&gt;21.05&lt;/code&gt; with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nix-channel --add https://nixos.org/channels/nixos-21.05 nixos
nix-channel --update&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then I changed the &lt;code&gt;configuration.nix&lt;/code&gt; to:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; system = {
    stateVersion = &amp;quot;21.05&amp;quot;;
  };&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dealing with channels is quite fragile, so I have these commands copied as comments in my &lt;code&gt;configuration.nix&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once configuration is done we can install nix:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb14-1&quot;&gt;&lt;a href=&quot;#cb14-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;nixos-install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Don’t worry, we can use &lt;code&gt;nixos-rebuild switch&lt;/code&gt; to reconfigure nix whenever, once we’re booted into it. Hopefully we boot successfully:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb15&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb15-1&quot;&gt;&lt;a href=&quot;#cb15-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;reboot&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Booting is hard, don’t worry if this goes wrong the first &lt;s&gt;10&lt;/s&gt; 30 times.&lt;/p&gt;
&lt;p&gt;You may need to enable UEFI in your BIOS. It’s up to the reader to figure that part out &lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;. Alternatively one could setup grub. Good luck with that. You can’t read the rest of this post until you’ve booted. Go back if you haven’t booted, you messed up.&lt;/p&gt;
&lt;h1 id=&quot;configure-nix-part-2-with-git&quot;&gt;Configure nix part 2, with git&lt;/h1&gt;
&lt;p&gt;Once we’re booted into the installation, the absolute paths for the symlinks are different. For example root is no longer under &lt;code&gt;/mnt&lt;/code&gt;, but under, well, root &lt;code&gt;/&lt;/code&gt;. So login as root&lt;a href=&quot;#fn4&quot; class=&quot;footnote-ref&quot; id=&quot;fnref4&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; and clone your config project:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb16&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb16-1&quot;&gt;&lt;a href=&quot;#cb16-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;bu&quot;&gt;cd&lt;/span&gt; /&lt;/span&gt;
&lt;span id=&quot;cb16-2&quot;&gt;&lt;a href=&quot;#cb16-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;git&lt;/span&gt; clone https://github.com/jappeace/linux-config&lt;/span&gt;
&lt;span id=&quot;cb16-3&quot;&gt;&lt;a href=&quot;#cb16-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;chown&lt;/span&gt; jappie:users &lt;span class=&quot;at&quot;&gt;-R&lt;/span&gt; /linux-config&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This puts the linux-config project on the &lt;code&gt;/linux-config&lt;/code&gt; path. Some old time linux/unix users may puke in their mouths upon seeing the “standard” directories being ignored, but fuck them. We mustn’t forget to copy over the hardware generated config into our git project:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb17&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb17-1&quot;&gt;&lt;a href=&quot;#cb17-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;cp&lt;/span&gt; /etc/nixos/hardware-configuration.nix /linux-config/hardware/branch-name.nix&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Where branch name the name is for the git branch you’ll use for this deployment. More on that in the branches section. Also we want to include this as a module in the &lt;code&gt;configuration.nix&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb18&quot;&gt;&lt;pre class=&quot;sourceCode nix&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb18-1&quot;&gt;&lt;a href=&quot;#cb18-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  imports = &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb18-2&quot;&gt;&lt;a href=&quot;#cb18-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ss&quot;&gt;./hardware/branch-name.nix&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-3&quot;&gt;&lt;a href=&quot;#cb18-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;]&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The tracked configuration should be used by the system. What I usually do is login as my own user, and run the script &lt;a href=&quot;https://github.com/jappeace/linux-config/blob/work-machine/scripts/nixos-setup.sh&quot;&gt;setup-nixos.sh&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb19&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb19-1&quot;&gt;&lt;a href=&quot;#cb19-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;bu&quot;&gt;exit&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-2&quot;&gt;&lt;a href=&quot;#cb19-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;bu&quot;&gt;cd&lt;/span&gt; /linux-config/scripts/&lt;/span&gt;
&lt;span id=&quot;cb19-3&quot;&gt;&lt;a href=&quot;#cb19-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;./setup-nixos.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which sets up the symlink from the git tracked configuration to the standard location, in other words it does this:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb20&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb20-1&quot;&gt;&lt;a href=&quot;#cb20-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-sf&lt;/span&gt; /linux-config/configuration.nix /etc/nixos/configuration.nix&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This script also symlinks all relevant dotfiles from linux config into the home folder. You may want prefer &lt;a href=&quot;https://github.com/nix-community/home-manager&quot;&gt;home manager&lt;/a&gt; to symlinking dotfiles. But this works for me.&lt;/p&gt;
&lt;h2 id=&quot;multiple-machines-desktops&quot;&gt;Multiple machines desktops&lt;/h2&gt;
&lt;p&gt;Branches are ideal for managing multiple machines, because it allows you to diverge oddities such as hardware specific configurations. For example I also have this crummy display switch script which is only relevant for the PC. On the laptop it has to be slightly different (if used at all).&lt;/p&gt;
&lt;p&gt;This branch setup also allows merging back configuration changes from other machines. Which involves solving an ordinary git conflict. I recommend the reader to use merges rather then rebases, because that way git remembers how conflicts are resolved.&lt;/p&gt;
&lt;p&gt;However I recently learned that a friend of mine handles this trough a &lt;a href=&quot;https://github.com/erikbackman/nixos-config/blob/master/flake.nix#L54&quot;&gt;module&lt;/a&gt; system. He then runs that with &lt;code&gt;nixos-rebuild --flake .#machine-name&lt;/code&gt;. So rather then using branches he has an entrypoint per machine which he calls out directly with the flake. I find his setup interesting, and may move over to something like that in the future, although since flakes are still experimental, I’ll hold off.&lt;/p&gt;
&lt;p&gt;Another alternative is multiple configuration.nix files in a repository and let the symlink decide which should be used for what machine. This would avoid any merge conflicts, although the versions between machines need to be similar. I think I prefer merge conflicts.&lt;/p&gt;
&lt;h1 id=&quot;secrets&quot;&gt;Secrets&lt;/h1&gt;
&lt;p&gt;I have three major secret sources. 1. ssh keys 2. gpg keys 3. The keepassxc database&lt;/p&gt;
&lt;p&gt;The database in &lt;a href=&quot;https://syncthing.net/&quot;&gt;synchting&lt;/a&gt;, this gives me access to all services so that I can simply generate new gpg and ssh keys per deployment. Any other file manage service would do, but I like syncthing because it’s decentralized.&lt;/p&gt;
&lt;p&gt;I go to https://localhost:8384 on some device that has the database, and the target device on the same address. I type over the device id into that screen to start syncing. after syncing completes I have access to the keepasscx database. Now I can generate new ssh keys and gpg keys, and login to services to update those. With that finished the installation is complete.&lt;/p&gt;
&lt;p&gt;Aside from getting the keypass database up and running, it’s important to add your newly generated public key to the services you manage. For example this website is hosted on the &lt;a href=&quot;%7Bfilename%7D/hetzner-nix-monolith.md&quot;&gt;nixos multi monolith&lt;/a&gt;. It be prudent to add the ssh key via a machine that already has access to it. Syncthing can also be used for this.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;I had uuid for my disks, but I swapped the disks so the boot bricked.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;press some f keys on boot, f11 or f2 maybe?&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;An issue I encountered was that rather then selecting EUFI boot, the bios did a traditional boot on the disk. So EUFI was correctly installed, I just had to select the same disk but with the EUFI label from the bios. Yup, all kinds of stuff can go wrong with booting.&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;Once rebooted you may be stuck at the display manager. Use &lt;code&gt;Alt+f1&lt;/code&gt; to switch to another TTY and login as root, then use &lt;code&gt;passwd your-user-name&lt;/code&gt; to set an initial password for that user. Use &lt;code&gt;Alt+f7&lt;/code&gt; to go back to the display manager.&lt;a href=&quot;#fnref4&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>A brief intro to MTL</title>
    <link href="https://jappieklooster.nl/a-brief-intro-to-mtl.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2021-08-10:/a-brief-intro-to-mtl.html</id>
    <published>2021-08-10T00:05:00Z</published>
    <updated>2021-08-10T09:50:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="technique"/>
    <summary type="html">&lt;figure&gt;
&lt;img src=&quot;images/2021/mtl.png&quot; alt=&quot;mtl-header&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;mtl-header&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Recently a blog post came out which I quite like, it describes how to use the concrete base &lt;a href=&quot;https://blog.cofree.coffee/2021-08-05-a-brief-intro-to-monad-transformers/&quot;&gt;transformers&lt;/a&gt;. It’s very thorough and gives a concrete example for using transformers. Although it looks quite low level and I think you’ll get more out of transformers by using full&lt;/p&gt;</summary>
    <content type="html">&lt;figure&gt;
&lt;img src=&quot;images/2021/mtl.png&quot; alt=&quot;mtl-header&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;mtl-header&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Recently a blog post came out which I quite like, it describes how to use the concrete base &lt;a href=&quot;https://blog.cofree.coffee/2021-08-05-a-brief-intro-to-monad-transformers/&quot;&gt;transformers&lt;/a&gt;. It’s very thorough and gives a concrete example for using transformers. Although it looks quite low level and I think you’ll get more out of transformers by using full MTL.&lt;/p&gt;
&lt;p&gt;That blogpost inspired me to write this, because I can’t find a succinct description on how to use MTL&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;. I learned MTL by staring at &lt;a href=&quot;https://hackage.haskell.org/package/reflex&quot;&gt;reflex&lt;/a&gt; for days, if not weeks. Which is an uncomfortable learning process. To make MTL more accessible I’ll give a brief overview of this style&lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;. I’ll write down how MTL works from the ground up, so people can &lt;em&gt;read&lt;/em&gt; how to use it rather then struggling with code for days like I did.&lt;/p&gt;
&lt;p&gt;If you like video presentations, I also presented how to use MTL in a &lt;a href=&quot;https://www.youtube.com/watch?v=MPlrAe-XYMU&amp;amp;t=300s&quot;&gt;video format&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-type-variable-m&quot;&gt;&lt;a id=&quot;intro&quot;&gt;&lt;/a&gt; The type variable &lt;code&gt;m&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;We start by introducing &lt;code&gt;m&lt;/code&gt;. Which could’ve been named &lt;code&gt;monad&lt;/code&gt; or &lt;code&gt;x&lt;/code&gt;, but the community settled on using &lt;code&gt;m&lt;/code&gt; for type variables with the &lt;code&gt;Monad&lt;/code&gt; constraint, so I will use this too. Normally we use type variable’s in concrete types, for example &lt;code&gt;Maybe a&lt;/code&gt; or &lt;code&gt;[a]&lt;/code&gt;. However, Instead of having our type variable inside a concrete type, we can also flip it around:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;moreMonad ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;moreMonad &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This compiles because the &lt;code&gt;Monad&lt;/code&gt; constraint on &lt;code&gt;m&lt;/code&gt; gives us the &lt;a href=&quot;https://hackage.haskell.org/package/base-4.15.0.0/docs/Control-Monad.html#v:return&quot;&gt;&lt;code&gt;return&lt;/code&gt;&lt;/a&gt; function &lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;. After you’re convinced this is a valid definition, let’s use it. What can we do with this &lt;code&gt;moreMonad&lt;/code&gt; binding? Well, we can pattern match on it:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;fiveTroughMaybe ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;fiveTroughMaybe &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; moreMonad &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;#cb2-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;#cb2-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;9&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;GHC will give &lt;code&gt;moreMonad&lt;/code&gt; the type &lt;code&gt;Maybe&lt;/code&gt; at this call site. GHC reasons backwards from the pattern match up to the &lt;code&gt;case moreMonad of&lt;/code&gt; definition to figure out the type. In my head I describe this backwards reasoning process as: “pretending you have a &lt;code&gt;Maybe&lt;/code&gt; which makes it becomes true”. So &lt;code&gt;fiveTroughMaybe&lt;/code&gt;results in 5 because &lt;code&gt;return&lt;/code&gt; is implemented as &lt;code&gt;Just&lt;/code&gt; on the &lt;code&gt;Maybe&lt;/code&gt; type’s &lt;code&gt;Monad&lt;/code&gt; instance.&lt;/p&gt;
&lt;p&gt;This is valid. You should convince yourself it’s valid. To convince yourself I’m not lying paste this code into GHCI before continuing, and gain some confidence, because yonder be dragons.&lt;/p&gt;
&lt;p&gt;Continuing now with the same module we can also pattern match on &lt;code&gt;Either&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;fiveTroughEither ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;#cb3-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;fiveTroughEither &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; moreMonad &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;#cb3-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Right&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;#cb3-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; _y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;9&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Both &lt;code&gt;fiveTroughMaybe&lt;/code&gt; and &lt;code&gt;fiveTroughEither&lt;/code&gt; will result in &lt;code&gt;5&lt;/code&gt;. This is allowed in the same module because &lt;code&gt;moreMonad&lt;/code&gt; will only get assigned the type at the &lt;a href=&quot;https://en.wikipedia.org/wiki/Call_site&quot;&gt;call site&lt;/a&gt;. The compiler figures out the type of &lt;code&gt;moreMonad&lt;/code&gt; by looking at usage per call site. This backwards ‘figuring out’ is normal for type variables.&lt;/p&gt;
&lt;h3 id=&quot;optional-mastery-exercise&quot;&gt;(optional) mastery exercise&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Can we always pattern match on every possible monad type like we just did with &lt;code&gt;Just&lt;/code&gt; or &lt;code&gt;Either&lt;/code&gt;? Can we always get the value out without being in the same monad? The answer is in the footnote. &lt;a href=&quot;#fn4&quot; class=&quot;footnote-ref&quot; id=&quot;fnref4&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- + GHC figures out here the types on callsite, what mechanism can be used 
to flip the reasoning direction of GHC?
RankNTypes? Existentials?
--&gt;
&lt;h2 id=&quot;transformers-as-constraints-on-m&quot;&gt;Transformers as constraints on &lt;code&gt;m&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;With that brief introduction, we can start applying this idea to the ‘&lt;a href=&quot;https://blog.cofree.coffee/2021-08-05-a-brief-intro-to-monad-transformers/&quot;&gt;“A Brief Intro to Monad Transformers” blogpost&lt;/a&gt;’ which inspired me to write this. In that blogpost, a newtype is constructed to hold the entire monad transformer stack like this:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;#cb4-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AppM&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AppM&lt;/span&gt; {&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;#cb4-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;    runAppM ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExceptT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;M.Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;)) a&lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;#cb4-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb4-4&quot;&gt;&lt;a href=&quot;#cb4-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;newtype&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;MonadError&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb4-5&quot;&gt;&lt;a href=&quot;#cb4-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                    &lt;span class=&quot;dt&quot;&gt;MonadState&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;M.Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I call this &lt;code&gt;AppM&lt;/code&gt; a concrete type because there is only one way to pattern match on it. We’re not allowed to pretend it’s a &lt;code&gt;Maybe&lt;/code&gt; for example. This definition is used in the &lt;code&gt;assignIndexToVariables&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;assignIndexToVariables ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AST&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Variables&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AppM&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;AST&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Instead of using the concrete type &lt;code&gt;AppM&lt;/code&gt;, we could use MTL type classes to describe what is needed. These type classes will become constraints on &lt;code&gt;m&lt;/code&gt;, similarly to how &lt;code&gt;Monad&lt;/code&gt; was a constraint on &lt;code&gt;m&lt;/code&gt; in the &lt;a href=&quot;#intro&quot;&gt;introduction&lt;/a&gt;. Which means we want to have &lt;a href=&quot;https://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-Except.html#t:MonadError&quot;&gt;&lt;code&gt;MonadError String&lt;/code&gt;&lt;/a&gt; as replacement for &lt;code&gt;ExceptT String&lt;/code&gt; &lt;a href=&quot;#fn5&quot; class=&quot;footnote-ref&quot; id=&quot;fnref5&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt;, and &lt;a href=&quot;https://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-State-Lazy.html#t:MonadState&quot;&gt;&lt;code&gt;MonadState (M.Map VariableName Int)&lt;/code&gt;&lt;/a&gt; as replacement for &lt;code&gt;State (M.Map VariableName Int)&lt;/code&gt;. Doing this will change the type signature of &lt;code&gt;assignIndexToVariables&lt;/code&gt; as follows:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;#cb6-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;assignIndexToVariables ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;#cb6-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;               &lt;span class=&quot;dt&quot;&gt;MonadError&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; m&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;#cb6-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadState&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;M.Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;) m&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;#cb6-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AST&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;#cb6-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Variables&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-6&quot;&gt;&lt;a href=&quot;#cb6-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;AST&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So what’s the difference? The type signature is more verbose, although we no longer need the newtype. In trade for this verbosity, we can use the monad stack in any order at the call site. Both invocations of running this code are now allowed:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;#cb7-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;main ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;#cb7-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;main &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;#cb7-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;#cb7-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;flip&lt;/span&gt; evalState &lt;span class=&quot;fu&quot;&gt;mempty&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; runExceptT &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-5&quot;&gt;&lt;a href=&quot;#cb7-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    assignIndexToVariables ast vars&lt;/span&gt;
&lt;span id=&quot;cb7-6&quot;&gt;&lt;a href=&quot;#cb7-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; runExcept &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;flip&lt;/span&gt; evalStateT &lt;span class=&quot;fu&quot;&gt;mempty&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-7&quot;&gt;&lt;a href=&quot;#cb7-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    assignIndexToVariables ast vars&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This wasn’t possible in the original code. We’ve told the compiler that the &lt;em&gt;order&lt;/em&gt; of a monad stack doesn’t matter. Which makes sense because consider two monad stacks:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;#cb8-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;at ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Char&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExceptT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;M.Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;)) &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;#cb8-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;bt ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;StateT&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;M.Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;Except&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;) &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These describe the same capabilities, however the compiler says &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; should &lt;em&gt;not&lt;/em&gt; compose. It’s impossible to write:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;#cb9-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ct ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Char&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; _ &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;#cb9-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ct &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; at &lt;span class=&quot;op&quot;&gt;&amp;gt;=&amp;gt;&lt;/span&gt; bt&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We don’t know what goes at &lt;code&gt;_&lt;/code&gt; for &lt;code&gt;ct&lt;/code&gt; because &lt;code&gt;at&lt;/code&gt; and &lt;code&gt;bt&lt;/code&gt; have concrete types. We can write this composition however if these signatures are defined in MTL style:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;#cb10-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;am ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadError&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; m&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;#cb10-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadState&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;M.Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;) m&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;#cb10-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Char&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-4&quot;&gt;&lt;a href=&quot;#cb10-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;bm ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadState&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;M.Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;) m&lt;/span&gt;
&lt;span id=&quot;cb10-5&quot;&gt;&lt;a href=&quot;#cb10-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadError&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; m&lt;/span&gt;
&lt;span id=&quot;cb10-6&quot;&gt;&lt;a href=&quot;#cb10-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-7&quot;&gt;&lt;a href=&quot;#cb10-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-8&quot;&gt;&lt;a href=&quot;#cb10-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;cm ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadState&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;M.Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;) m&lt;/span&gt;
&lt;span id=&quot;cb10-9&quot;&gt;&lt;a href=&quot;#cb10-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadError&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; m&lt;/span&gt;
&lt;span id=&quot;cb10-10&quot;&gt;&lt;a href=&quot;#cb10-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Char&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-11&quot;&gt;&lt;a href=&quot;#cb10-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;cm &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; am &lt;span class=&quot;op&quot;&gt;&amp;gt;=&amp;gt;&lt;/span&gt; bm&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because constraints don’t specify an order on transformers, the MTL style function definition can compose. &lt;a href=&quot;#fn6&quot; class=&quot;footnote-ref&quot; id=&quot;fnref6&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;6&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This section described the core idea of MTL. In the following sections we’re going to extend MTL using type error driven development. This all sound like madness if you don’t try it out with a compiler. And I feel understanding errors is a large part of understanding MTL. The type errors are difficult to decipher. I’ve made an &lt;a href=&quot;https://github.com/jappeace/mtl-src/blob/master/src/Lib.hs&quot;&gt;reference project&lt;/a&gt; so the reader can verify the truth of my claims.&lt;/p&gt;
&lt;p&gt;Even though you may doubt me dear reader, let’s go deeper into the &lt;a href=&quot;images/2021/abyss.jpeg&quot;&gt;abyss&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;optional-mastery-exercises&quot;&gt;(optional) mastery exercises&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;What does the function &lt;a href=&quot;https://hackage.haskell.org/package/transformers-0.6.0.2/docs/Control-Monad-Trans-Class.html#v:lift&quot;&gt;&lt;code&gt;lift&lt;/code&gt;&lt;/a&gt; do? The answer is in the footnotes. &lt;a href=&quot;#fn7&quot; class=&quot;footnote-ref&quot; id=&quot;fnref7&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;7&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is the order of a transformer stack always irrelevant? The answer is in the footnotes. &lt;a href=&quot;#fn8&quot; class=&quot;footnote-ref&quot; id=&quot;fnref8&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;8&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Say &lt;code&gt;ct&lt;/code&gt; has this type signature:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  ct :: Char 
     -&amp;gt; ExceptT String (State (M.Map VariableName Int)) String&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Call &lt;code&gt;at&lt;/code&gt; and then &lt;code&gt;bt&lt;/code&gt; from within &lt;code&gt;ct&lt;/code&gt; such that it composes like the fish operator &lt;a href=&quot;https://hackage.haskell.org/package/base-4.15.0.0/docs/Control-Monad.html#v:-62--61--62-&quot;&gt;&lt;code&gt;&amp;gt;=&amp;gt;&lt;/code&gt;&lt;/a&gt; would with help of &lt;a href=&quot;https://hackage.haskell.org/package/monad-control-1.0.3.1/docs/Control-Monad-Trans-Control.html#v:liftWith&quot;&gt;&lt;code&gt;liftWith&lt;/code&gt;&lt;/a&gt;. For additional background see &lt;a href=&quot;https://lexi-lambda.github.io/blog/2019/09/07/demystifying-monadbasecontrol/&quot;&gt;this blogpost&lt;/a&gt;. The answer can be found in the &lt;a href=&quot;https://github.com/jappeace/mtl-src/blob/master/src/Lib.hs&quot;&gt;reference project&lt;/a&gt; under the binding &lt;code&gt;answer&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;lose-and-tight-constraints&quot;&gt;&lt;a id=&quot;lose-tight-constraints&quot;&gt;&lt;/a&gt; Lose and tight constraints&lt;/h2&gt;
&lt;p&gt;Say we want to use &lt;code&gt;moreMonad&lt;/code&gt; from the &lt;a href=&quot;#intro&quot;&gt;introduction&lt;/a&gt; in &lt;code&gt;assignIndexToVariables&lt;/code&gt;. I call &lt;code&gt;moreMonad&lt;/code&gt; a tightly constrained binding. It’s only allowed to use what &lt;code&gt;Monad&lt;/code&gt; typeclass provides. &lt;code&gt;assignIndexToVariables&lt;/code&gt; on the other hand is less tightly constrained, since it has &lt;code&gt;Monad&lt;/code&gt; by implication, and also everything in &lt;code&gt;MonadError&lt;/code&gt; and &lt;code&gt;MonadState&lt;/code&gt;. So let’s use it:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;#cb12-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;assignIndexToVariables ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-2&quot;&gt;&lt;a href=&quot;#cb12-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;MonadError&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-3&quot;&gt;&lt;a href=&quot;#cb12-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;MonadState&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;M.Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;) m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-4&quot;&gt;&lt;a href=&quot;#cb12-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;AST&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Variables&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;AST&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb12-5&quot;&gt;&lt;a href=&quot;#cb12-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;assignIndexToVariables _ _ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-6&quot;&gt;&lt;a href=&quot;#cb12-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   _z &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; moreMonad &lt;/span&gt;
&lt;span id=&quot;cb12-7&quot;&gt;&lt;a href=&quot;#cb12-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This would just work, because both &lt;a href=&quot;https://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-Except.html&quot;&gt;&lt;code&gt;MonadError&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-State-Class.html#t:MonadState&quot;&gt;&lt;code&gt;MonadState&lt;/code&gt;&lt;/a&gt; imply &lt;code&gt;Monad&lt;/code&gt; in their definitions. In mtl style, the functions with &lt;em&gt;tighter&lt;/em&gt; constraints can be used in &lt;em&gt;more&lt;/em&gt; situations without any refactoring.&lt;/p&gt;
&lt;p&gt;Now we’re going to do the complete opposite. The most lax constraint possible is &lt;code&gt;MonadIO&lt;/code&gt;, which gives access to arbitrary &lt;code&gt;IO&lt;/code&gt; trough the &lt;code&gt;liftIO&lt;/code&gt; function. I’m not casting judgement, I just want to show what happens. So let’s add a &lt;a href=&quot;https://en.wikipedia.org/wiki/MacGyver&quot;&gt;MacGyver&lt;/a&gt; &lt;a href=&quot;#fn9&quot; class=&quot;footnote-ref&quot; id=&quot;fnref9&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;9&lt;/sup&gt;&lt;/a&gt; logging function as follows:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb13&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb13-1&quot;&gt;&lt;a href=&quot;#cb13-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;macGyverLog ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadIO&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m ()&lt;/span&gt;
&lt;span id=&quot;cb13-2&quot;&gt;&lt;a href=&quot;#cb13-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;macGyverLog msg &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; liftIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;putStrLn&lt;/span&gt; msg&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The code is perfect. Y’know, it misses some things you’d expect from your regular logging library such as code positions, time stamping, etc. But that’s why it’s called &lt;code&gt;macGyverLog&lt;/code&gt; and not &lt;code&gt;kitchenSinkLog&lt;/code&gt;. And if we did some introspection we may find our code tends to look a lot more like &lt;code&gt;macGyverLog&lt;/code&gt; then &lt;code&gt;kitchenSinkLog&lt;/code&gt;, so let’s throw it into production:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb14-1&quot;&gt;&lt;a href=&quot;#cb14-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;assignIndexToVariables ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-2&quot;&gt;&lt;a href=&quot;#cb14-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;MonadError&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-3&quot;&gt;&lt;a href=&quot;#cb14-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;MonadState&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;M.Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;) m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-4&quot;&gt;&lt;a href=&quot;#cb14-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;AST&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Variables&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;AST&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb14-5&quot;&gt;&lt;a href=&quot;#cb14-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;assignIndexToVariables _ _ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-6&quot;&gt;&lt;a href=&quot;#cb14-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   macGyverLog &lt;span class=&quot;st&quot;&gt;&amp;quot;Starting reading more monad&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-7&quot;&gt;&lt;a href=&quot;#cb14-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   _z &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; moreMonad &lt;/span&gt;
&lt;span id=&quot;cb14-8&quot;&gt;&lt;a href=&quot;#cb14-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   macGyverLog &lt;span class=&quot;st&quot;&gt;&amp;quot;End reading more monad&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-9&quot;&gt;&lt;a href=&quot;#cb14-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will cause the following type error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;src/Lib.hs:31:5: error:
    • Could not deduce (MonadIO m) arising from a use of ‘macGyverLog’
      from the context: (MonadError String m,
                         MonadState (M.Map VariableName Int) m)
        bound by the type signature for:
                   assignIndexToVariables :: forall (m :: * -&amp;gt; *).
                                             (MonadError String m,
                                              MonadState (M.Map VariableName Int) m) =&amp;gt;
                                             AST VariableName -&amp;gt; Variables -&amp;gt; m (AST Int)
        at src/Lib.hs:(26,1)-(29,46)
      Possible fix:
        add (MonadIO m) to the context of
          the type signature for:
            assignIndexToVariables :: forall (m :: * -&amp;gt; *).
                                      (MonadError String m,
                                       MonadState (M.Map VariableName Int) m) =&amp;gt;
                                      AST VariableName -&amp;gt; Variables -&amp;gt; m (AST Int)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The possible fix read in the type error is correct, but we have to know what a context is, and a type signature to decipher that error message&lt;a href=&quot;#fn10&quot; class=&quot;footnote-ref&quot; id=&quot;fnref10&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;10&lt;/sup&gt;&lt;/a&gt;. The compiler is saying in incomprohensible error speak that you need to add a constraint &lt;code&gt;MonadIO m&lt;/code&gt; like so:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb16&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb16-1&quot;&gt;&lt;a href=&quot;#cb16-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;assignIndexToVariables ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-2&quot;&gt;&lt;a href=&quot;#cb16-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;MonadIO&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-3&quot;&gt;&lt;a href=&quot;#cb16-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;MonadError&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-4&quot;&gt;&lt;a href=&quot;#cb16-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;MonadState&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;M.Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;) m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-5&quot;&gt;&lt;a href=&quot;#cb16-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;AST&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Variables&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;AST&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Cryptic as it may be, the reason I’m writing about this isn’t that particular error message, it’s the next one:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;src/Lib.hs:51:50: error:
    • No instance for (MonadIO Data.Functor.Identity.Identity)
        arising from a use of ‘assignIndexToVariables’
    • In the second argument of ‘($)’, namely
        ‘assignIndexToVariables ast vars’
      In the second argument of ‘($)’, namely
        ‘runExceptT $ assignIndexToVariables ast vars’
      In the second argument of ‘($)’, namely
        ‘flip evalState mempty
           $ runExceptT $ assignIndexToVariables ast vars’
   |
51 |     print $ flip evalState mempty $ runExceptT $ assignIndexToVariables ast vars
   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here you may start thinking, WTF. Rightfully so. The reason it starts talking about identity is because evalState &lt;em&gt;runs in identity&lt;/em&gt;. Look at the haddocks for &lt;a href=&quot;https://hackage.haskell.org/package/transformers-0.6.0.2/docs/Control-Monad-Trans-State-Lazy.html#v:evalState&quot;&gt;&lt;code&gt;evalState&lt;/code&gt;&lt;/a&gt;, then click on &lt;a href=&quot;https://hackage.haskell.org/package/transformers-0.6.0.2/docs/Control-Monad-Trans-State-Lazy.html#t:State&quot;&gt;&lt;code&gt;State&lt;/code&gt;&lt;/a&gt;. The base monad is identity. How do we fix this? First we replace &lt;code&gt;Identity&lt;/code&gt; with a gap by invoking &lt;code&gt;evalStateT&lt;/code&gt; instead of &lt;code&gt;evalState&lt;/code&gt; (note the &lt;code&gt;T&lt;/code&gt;). This will result in the following beauty &lt;a id=&quot;shes-a-beauty&quot;&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;src/Lib.hs:51:5: error:
    • Ambiguous type variable ‘m0’ arising from a use of ‘print’
      prevents the constraint ‘(Show
                                  (m0 (Either String (AST Int))))’ from being solved.
      Probable fix: use a type annotation to specify what ‘m0’ should be.
      These potential instances exist:
        instance (Show a, Show b) =&amp;gt; Show (Either a b)
          -- Defined in ‘Data.Either’
        instance (Show k, Show a) =&amp;gt; Show (M.Map k a)
          -- Defined in ‘Data.Map.Internal’
        instance Show a =&amp;gt; Show (AST a) -- Defined at src/Lib.hs:21:13
        ...plus 18 others
        ...plus 9 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In a stmt of a &amp;#39;do&amp;#39; block:
        print
          $ flip evalStateT mempty
              $ runExceptT $ assignIndexToVariables ast vars
      In the expression:
        do print
             $ flip evalStateT mempty
                 $ runExceptT $ assignIndexToVariables ast vars
           print (eitherFive, maybeFive)
      In the expression:
        let
          vars = S.fromList [...]
          ast
            = Node (Leaf &amp;quot;a&amp;quot;) (Node (Leaf &amp;quot;b&amp;quot;) (Node (Leaf &amp;quot;a&amp;quot;) (Leaf &amp;quot;c&amp;quot;)))
        in
          do print
               $ flip evalStateT mempty
                   $ runExceptT $ assignIndexToVariables ast vars
             print (eitherFive, maybeFive)
   |
51 |     print $ flip evalStateT mempty $ runExceptT $ assignIndexToVariables ast vars
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/Lib.hs:51:18: error:
    • Ambiguous type variable ‘m0’ arising from a use of ‘evalStateT’
      prevents the constraint ‘(Monad m0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘m0’ should be.
      These potential instances exist:
        instance Monad (Either e) -- Defined in ‘Data.Either’
        instance Monad IO -- Defined in ‘GHC.Base’
        instance [safe] Monad m =&amp;gt; Monad (ExceptT e m)
          -- Defined in ‘Control.Monad.Trans.Except’
        ...plus six others
        ...plus 16 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the first argument of ‘flip’, namely ‘evalStateT’
      In the expression: flip evalStateT mempty
      In the second argument of ‘($)’, namely
        ‘flip evalStateT mempty
           $ runExceptT $ assignIndexToVariables ast vars’
   |
51 |     print $ flip evalStateT mempty $ runExceptT $ assignIndexToVariables ast vars
   |                  ^^^^^^^^^^

src/Lib.hs:51:51: error:
    • Ambiguous type variable ‘m0’ arising from a use of ‘assignIndexToVariables’
      prevents the constraint ‘(MonadIO m0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘m0’ should be.
      These potential instances exist:
        instance [safe] MonadIO IO -- Defined in ‘Control.Monad.IO.Class’
        instance [safe] MonadIO m =&amp;gt; MonadIO (ExceptT e m)
          -- Defined in ‘Control.Monad.Trans.Except’
        instance [safe] MonadIO m =&amp;gt; MonadIO (StateT s m)
          -- Defined in ‘Control.Monad.Trans.State.Lazy’
        ...plus 11 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the second argument of ‘($)’, namely
        ‘assignIndexToVariables ast vars’
      In the second argument of ‘($)’, namely
        ‘runExceptT $ assignIndexToVariables ast vars’
      In the second argument of ‘($)’, namely
        ‘flip evalStateT mempty
           $ runExceptT $ assignIndexToVariables ast vars’
   |
51 |     print $ flip evalStateT mempty $ runExceptT $ assignIndexToVariables ast vars
   |                                                   ^^^^^^^^^^^^^^^^^^^&lt;/code&gt;&lt;/pre&gt;
&lt;!-- Oh ghci, I love it when you talk to me this way. --&gt;
&lt;p&gt;All these &lt;code&gt;m0&lt;/code&gt; occur because we introduced the gap, GHC has no idea what the base monad is at this point. Which is what we want. Let’s solve it all in one change:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb19&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb19-1&quot;&gt;&lt;a href=&quot;#cb19-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;flip&lt;/span&gt; evalStateT &lt;span class=&quot;fu&quot;&gt;mempty&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-2&quot;&gt;&lt;a href=&quot;#cb19-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        (runExceptT &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; assignIndexToVariables ast vars)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that we replaced the application of &lt;code&gt;$&lt;/code&gt; to a bind &lt;code&gt;=&amp;lt;&amp;lt;&lt;/code&gt;. The base monad is now &lt;code&gt;IO&lt;/code&gt; instead of &lt;code&gt;Identity&lt;/code&gt;, which solves everything. It’s solved because &lt;code&gt;IO&lt;/code&gt;, surprise, surprise, has an instance of &lt;code&gt;MonadIO&lt;/code&gt;! Who would’ve thought &lt;code&gt;liftIO&lt;/code&gt; could be &lt;code&gt;id&lt;/code&gt;. The readers’ keen eye spots a pattern: We merely select instances with types that have code attached to them. It’s code generation based on type selection.&lt;/p&gt;
&lt;h2 id=&quot;reinterpreting-io-or-the-mtl-style&quot;&gt;Reinterpreting IO or the MTL style&lt;/h2&gt;
&lt;p&gt;In most situations &lt;code&gt;MonadIO&lt;/code&gt; is fine. However it doesn’t allow us to reinterpret effects that are using &lt;code&gt;IO&lt;/code&gt;. An example of reinterpretation is a test where you would want to measure how often the &lt;code&gt;mcGyverLog&lt;/code&gt; function is being called. This section will show you how to do that.&lt;/p&gt;
&lt;p&gt;First we start by MTL-izing our &lt;code&gt;IO&lt;/code&gt; based code. How can we rewrite &lt;code&gt;mcGyverLog&lt;/code&gt; so that it doesn’t use &lt;code&gt;IO&lt;/code&gt; explicetly? The function that needs &lt;code&gt;IO&lt;/code&gt; is &lt;code&gt;putStrLn&lt;/code&gt;. It’s type signature is &lt;code&gt;String -&amp;gt; IO ()&lt;/code&gt;. We want that &lt;code&gt;IO&lt;/code&gt; to be an &lt;code&gt;m&lt;/code&gt;, so we introduce a new typeclass for our &lt;a href=&quot;https://hackage.haskell.org/package/monad-logger-0.3.36/docs/Control-Monad-Logger.html#t:MonadLogger&quot;&gt;not invented here&lt;/a&gt; log:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb20&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb20-1&quot;&gt;&lt;a href=&quot;#cb20-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NotInventedHereLog&lt;/span&gt; m &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-2&quot;&gt;&lt;a href=&quot;#cb20-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;    nihLog ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We already know what implementation &lt;code&gt;m&lt;/code&gt; has if it’s an &lt;code&gt;IO&lt;/code&gt; instance:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb21&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb21-1&quot;&gt;&lt;a href=&quot;#cb21-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NotInventedHereLog&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-2&quot;&gt;&lt;a href=&quot;#cb21-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;    nihLog ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb21-3&quot;&gt;&lt;a href=&quot;#cb21-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    nihLog &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;putStrLn&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To make our previous example work we need to replace &lt;code&gt;MonadIO&lt;/code&gt; in our function definition with &lt;code&gt;NotInventedHereLog&lt;/code&gt;. Because we renamed the &lt;code&gt;macGyverLog&lt;/code&gt; function to &lt;code&gt;nihLog&lt;/code&gt;, we need to replace those calls with &lt;code&gt;nihLog&lt;/code&gt; as well:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb22&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb22-1&quot;&gt;&lt;a href=&quot;#cb22-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;assignIndexToVariables2 ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-2&quot;&gt;&lt;a href=&quot;#cb22-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;NotInventedHereLog&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-3&quot;&gt;&lt;a href=&quot;#cb22-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;MonadError&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-4&quot;&gt;&lt;a href=&quot;#cb22-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;MonadState&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;M.Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;) m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-5&quot;&gt;&lt;a href=&quot;#cb22-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;AST&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VariableName&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Variables&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;AST&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb22-6&quot;&gt;&lt;a href=&quot;#cb22-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;assignIndexToVariables2 ast variables &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; forM ast &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \var &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-7&quot;&gt;&lt;a href=&quot;#cb22-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    nihLog &lt;span class=&quot;st&quot;&gt;&amp;quot;start more monad&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-8&quot;&gt;&lt;a href=&quot;#cb22-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    _z &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; moreMonad&lt;/span&gt;
&lt;span id=&quot;cb22-9&quot;&gt;&lt;a href=&quot;#cb22-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Running this will give us the following type error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;src/Lib.hs:54:52: error:
    • No instance for (NotInventedHereLog
                         (StateT (M.Map VariableName Int) (ExceptT [Char] IO)))
        arising from a use of ‘assignIndexToVariables2’
    • In the second argument of ‘($)’, namely
        ‘assignIndexToVariables2 ast vars’
      In the first argument of ‘runExceptT’, namely
        ‘(flip evalStateT mempty $ assignIndexToVariables2 ast vars)’
      In the second argument of ‘(=&amp;lt;&amp;lt;)’, namely
        ‘runExceptT
           (flip evalStateT mempty $ assignIndexToVariables2 ast vars)’
   |
54 |     print =&amp;lt;&amp;lt; runExceptT (flip evalStateT mempty $ assignIndexToVariables2 ast vars)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This looks scary, maybe this is the one, the one type error I can’t solve? After all, I’ve been waiting for that one perfect type error for over four years now. But no, this is known as the &lt;a href=&quot;http://felixmulder.com/writing/2020/08/08/Revisiting-application-structure#the-n2-issue&quot;&gt;&lt;span class=&quot;math inline&quot;&gt;&lt;em&gt;n&lt;/em&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/span&gt;-instances problem&lt;/a&gt;&lt;a href=&quot;#fn11&quot; class=&quot;footnote-ref&quot; id=&quot;fnref11&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;11&lt;/sup&gt;&lt;/a&gt;, which sounds very impressive. However for now we completely ignore that problem by providing an instance which solves this type error:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb24&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb24-1&quot;&gt;&lt;a href=&quot;#cb24-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;NotInventedHereLog&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NotInventedHereLog&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;StateT&lt;/span&gt; s m) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-2&quot;&gt;&lt;a href=&quot;#cb24-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  nihLog &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; lift &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; nihLog&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This code says: If you’re a &lt;code&gt;StateT&lt;/code&gt; and your base monad already has a &lt;code&gt;NotInventedHereLog&lt;/code&gt; constraint, you also have &lt;code&gt;NotInvnetedHereLog&lt;/code&gt; instance with help of &lt;a href=&quot;https://hackage.haskell.org/package/transformers-0.6.0.2/docs/Control-Monad-Trans-Class.html#v:lift&quot;&gt;&lt;code&gt;lift&lt;/code&gt;&lt;/a&gt;. By providing this instance we’re generating lift calls over &lt;code&gt;StateT&lt;/code&gt; for all occurrences of &lt;code&gt;niLog&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Moving on we get the same error for &lt;code&gt;ExceptT&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;src/Lib.hs:54:52: error:
    • No instance for (NotInventedHereLog (ExceptT [Char] IO))
        arising from a use of ‘assignIndexToVariables2’
    • In the second argument of ‘($)’, namely
        ‘assignIndexToVariables2 ast vars’
      In the first argument of ‘runExceptT’, namely
        ‘(flip evalStateT mempty $ assignIndexToVariables2 ast vars)’
      In the second argument of ‘(=&amp;lt;&amp;lt;)’, namely
        ‘runExceptT
           (flip evalStateT mempty $ assignIndexToVariables2 ast vars)’
   |
54 |     print =&amp;lt;&amp;lt; runExceptT (flip evalStateT mempty $ assignIndexToVariables2 ast vars)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will keep getting these errors for every unique transformer we use because of the &lt;a href=&quot;http://felixmulder.com/writing/2020/08/08/Revisiting-application-structure#the-n2-issue&quot;&gt;&lt;span class=&quot;math inline&quot;&gt;&lt;em&gt;n&lt;/em&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/span&gt;-instances problem&lt;/a&gt;&lt;a href=&quot;#fn12&quot; class=&quot;footnote-ref&quot; id=&quot;fnref12&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;12&lt;/sup&gt;&lt;/a&gt;. This blogpost isn’t about solving the &lt;span class=&quot;math inline&quot;&gt;&lt;em&gt;n&lt;/em&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/span&gt; problem, so I will ignore it. The solution to the type error however is pretty much the same:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb26&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb26-1&quot;&gt;&lt;a href=&quot;#cb26-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;NotInventedHereLog&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NotInventedHereLog&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ExceptT&lt;/span&gt; e m) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-2&quot;&gt;&lt;a href=&quot;#cb26-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  nihLog &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; lift &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; nihLog&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The example code will compile with these two additional instances. However we still don’t know how to reinterpret this purely, and we have introduced code duplication. This duplication can be removed with the default mechanism described in Alexis King her &lt;a href=&quot;https://lexi-lambda.github.io/blog/2017/04/28/lifts-for-free-making-mtl-typeclasses-derivable/&quot;&gt;blogpost&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For the pure interpretation we need to introduce a newtype, which is used to attach an instance for &lt;code&gt;NotInventedHereLog&lt;/code&gt;. This type’s instance will collect the logged messages. Turns out that the &lt;code&gt;WriterT&lt;/code&gt; monad transformer does exactly what we want. So the pure code will look like this:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb27&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb27-1&quot;&gt;&lt;a href=&quot;#cb27-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NihLogT&lt;/span&gt; m a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MkNihLogT&lt;/span&gt; {&lt;/span&gt;
&lt;span id=&quot;cb27-2&quot;&gt;&lt;a href=&quot;#cb27-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;        runNihLog ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;WriterT&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;] m a&lt;/span&gt;
&lt;span id=&quot;cb27-3&quot;&gt;&lt;a href=&quot;#cb27-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    } &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;MonadTrans&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;MonadWriter&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;])&lt;/span&gt;
&lt;span id=&quot;cb27-4&quot;&gt;&lt;a href=&quot;#cb27-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-5&quot;&gt;&lt;a href=&quot;#cb27-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NotInventedHereLog&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;NihLogT&lt;/span&gt; m) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-6&quot;&gt;&lt;a href=&quot;#cb27-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  nihLog msg &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; tell [msg]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The instance simply &lt;a href=&quot;https://hackage.haskell.org/package/mtl-2.2.2/docs/src/Control.Monad.Writer.Class.html#tell&quot;&gt;&lt;code&gt;tell&lt;/code&gt;&lt;/a&gt;’s the message, which &lt;code&gt;mappends&lt;/code&gt; it to the list. To run this code we use &lt;code&gt;runNihLog&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb28&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb28-1&quot;&gt;&lt;a href=&quot;#cb28-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; pureCode ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;AST&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;),  [&lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;])&lt;/span&gt;
&lt;span id=&quot;cb28-2&quot;&gt;&lt;a href=&quot;#cb28-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        pureCode &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; runWriter &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; runNihLog &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; runExceptT (&lt;span class=&quot;fu&quot;&gt;flip&lt;/span&gt; evalStateT &lt;span class=&quot;fu&quot;&gt;mempty&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; assignIndexToVariables2 ast vars)&lt;/span&gt;
&lt;span id=&quot;cb28-3&quot;&gt;&lt;a href=&quot;#cb28-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        (eitherAst, allLoggedMessages) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; pureCode &lt;/span&gt;
&lt;span id=&quot;cb28-4&quot;&gt;&lt;a href=&quot;#cb28-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; pureCode&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now &lt;code&gt;allLoggedMessages&lt;/code&gt; will contain all messages emitted by &lt;code&gt;nihLog&lt;/code&gt;. With this you can write property tests on &lt;code&gt;assignIndexToVariables2&lt;/code&gt;. For example you could assert that an AST of size 20 should emit at least 40 log messages. Obviously this isn’t limited to tests or purity, you could also add a newtype that has a connection pool to send the messages to some database for example.&lt;/p&gt;
&lt;p&gt;I’ll tap out here. This was supposed to be a short note on someone else’s blogpost, which spiraled into dumping all my knowledge here on MTL and extending it a bit as well. For example I didn’t even know about the defaults mechanism &lt;a href=&quot;https://lexi-lambda.github.io/blog/2017/04/28/lifts-for-free-making-mtl-typeclasses-derivable/&quot;&gt;Alexis wrote about&lt;/a&gt;. I’ll tap out here, thanks for reading.&lt;/p&gt;
&lt;p&gt;Let me know if you have any strong opinions on this style. Love it or hate it, I’d like to know! Or if you need any help using it. I’m interested in effect systems in general. Also let me know about your favorite effect system that I didn’t acknowledge.&lt;/p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Inspirational &lt;a href=&quot;https://blog.cofree.coffee/2021-08-05-a-brief-intro-to-monad-transformers/&quot;&gt;blogpost&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A functional example is available &lt;a href=&quot;https://github.com/jappeace/mtl-src/blob/master/src/Lib.hs&quot;&gt;here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=MPlrAe-XYMU&amp;amp;t=300s&quot;&gt;A video presentation on the exact same topic.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Full mtl style reinterpretation test &lt;a href=&quot;https://github.com/lexi-lambda/mtl-style-example&quot;&gt;example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;And a &lt;a href=&quot;https://lexi-lambda.github.io/blog/2017/06/29/unit-testing-effectful-haskell-with-monad-mock/&quot;&gt;library&lt;/a&gt; for mocking around mtl style, also gives more background.&lt;/li&gt;
&lt;li&gt;If I didn’t manage to exhaust you, here is more &lt;a href=&quot;https://ocharles.org.uk/posts/2016-01-26-transformers-free-monads-mtl-laws.html&quot;&gt;background&lt;/a&gt; and alternatives.&lt;/li&gt;
&lt;/ul&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;The best I could find is this &lt;a href=&quot;http://felixmulder.com/writing/2020/08/08/Revisiting-application-structure#the-n2-issue&quot;&gt;blogpost&lt;/a&gt;, which is more an experience report rather then an explanation of what’s going on. &lt;a href=&quot;https://ocharles.org.uk/posts/2016-01-26-transformers-free-monads-mtl-laws.html&quot;&gt;Ocharles&lt;/a&gt; could also be said to be talking about the subject, but it’s not an introduction, it’s an expert reference.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;Aren’t transformers the same as mtl? No! Back in the stone ages, people weren’t sure what the right approach would be to doing this, and frankly people still aren’t sure. The base package is the &lt;a href=&quot;https://hackage.haskell.org/package/transformers&quot;&gt;transformers package&lt;/a&gt;. Although the &lt;a href=&quot;https://hackage.haskell.org/package/mtl&quot;&gt;mtl package&lt;/a&gt; is most popular, there is also &lt;a href=&quot;https://hackage.haskell.org/package/mtl-tf&quot;&gt;mtl-tf&lt;/a&gt;. &lt;a href=&quot;https://hackage.haskell.org/package/polysemy&quot;&gt;Polysemy&lt;/a&gt; also builds on top of transformers. I think the subject of best approach is a subject for debate. I’d like to point out as well that in technology, popularity means nothing. Cobol used to be more popular then C up till the 1990’s, and is practically dead now. JavaScript is also more popular then Haskell, is it therefore better?&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;Note that although this is valid haskell, in practice it’s nonsense to write anything with just a &lt;code&gt;Monad&lt;/code&gt; constraint. I’m saying this because the constraint is &lt;a href=&quot;#lose-tight-constraints&quot;&gt;too tight&lt;/a&gt;! You can’t do anything in just a monad. I’m only showing it here to raise a point. In this situation it would’ve made more sense to drop the entire monad sharade and assign 5 directly with type of &lt;code&gt;Int&lt;/code&gt;.&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;No it’s not possible if a constructor isn’t exposed. Reflex uses this with &lt;a href=&quot;https://hackage.haskell.org/package/reflex-0.8.1.0/docs/Reflex-Dynamic.html#t:Dynamic&quot;&gt;&lt;code&gt;Dynamic t&lt;/code&gt;&lt;/a&gt; to create a smart destructor. In reflex you can only use a value in a dynamic by putting an entire monadic action inside the dynamic, and then using &lt;a href=&quot;https://hackage.haskell.org/package/reflex-dom-core-0.6.2.0/docs/Reflex-Dom-Widget-Basic.html#v:dyn&quot;&gt;&lt;code&gt;dyn&lt;/code&gt;&lt;/a&gt; to get it out (for reflex-dom at least, sdl uses something different). I’m highlighting this because I feel this is a powerful idea.&lt;a href=&quot;#fnref4&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn5&quot;&gt;&lt;p&gt;Why MonadError and ExceptT don’t share their names? It’s explained &lt;a href=&quot;https://www.reddit.com/r/haskell/comments/3ded39/why_cant_we_have_an_eithert_in_transformers/ct4mnk1/&quot;&gt;here&lt;/a&gt;.&lt;a href=&quot;#fnref5&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn6&quot;&gt;&lt;p&gt;We’ve not solved the &lt;a href=&quot;https://blog.cofree.coffee/2021-08-05-a-brief-intro-to-monad-transformers/#cb5&quot;&gt;problem&lt;/a&gt; here of being able to write a &lt;code&gt;Compose&lt;/code&gt; &lt;code&gt;Monad&lt;/code&gt; instance at all. We just kind of worked around it by not talking about order. It’s truly an awful hack, which are the best.&lt;a href=&quot;#fnref6&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn7&quot;&gt;&lt;p&gt;It allows concrete monad transformer selection, For example : &lt;code&gt;haskell   x :: LogginT (ReaderT AppContext Maybe) String   x = do callInLoggingT lift $ callInReaderT lift $ lift $ callInMaybe&lt;/code&gt; AppM from the original blogpost didn’t have to do this because the deriving mechanism generated the instances that in turn generate the lift calls.&lt;a href=&quot;#fnref7&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn8&quot;&gt;&lt;p&gt;No! It just happens to be irrelevant for most transformers in the transformers package. For example there exist the transformer &lt;a href=&quot;https://hackage.haskell.org/package/resourcet&quot;&gt;ResourceT&lt;/a&gt;. I encountered a production bug due to wrong order of running the transformer stack. Only large queries crashed with an opaque message &lt;code&gt;StatementAlreadyFinalized&lt;/code&gt;. The &lt;a href=&quot;https://hackage.haskell.org/package/persistent-2.13.1.1/docs/Database-Persist-Class.html#v:selectSourceRes&quot;&gt;&lt;code&gt;selectSource&lt;/code&gt;&lt;/a&gt; exposes the resource constraint. We also had a typeclass to embed that &lt;code&gt;ReaderT backend&lt;/code&gt; into the constraints, since it’s just a regular reader after all (it’s not quite). We also had an instance that said order of this &lt;code&gt;ResourceT&lt;/code&gt; and &lt;code&gt;ReaderT backend&lt;/code&gt; didn’t matter, but it did. This instance caused the running of the query to leak outside of the &lt;code&gt;runResourceT&lt;/code&gt; block. Removing the instance and being explicit about order solved the bug.&lt;a href=&quot;#fnref8&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn9&quot;&gt;&lt;p&gt;MacGyver is a TV character who was known to get out of precarious situations with absurdly little in terms of resources and a lot of improvisation, our logging function feels similar at this point. Another term that could’ve been used was Not Invented Here, but I liked MacGyver better.&lt;a href=&quot;#fnref9&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn10&quot;&gt;&lt;p&gt;The thing that baffles me is that GHC already manages to print your own code, they figure out the right constraint, why don’t they just give the example like I’m doing here with the message “try doing this:”. Instead they talk about constraints and contexts. Do they hate people using their language or something? I feel George Orwell’s &lt;a href=&quot;https://lhsblogs.typepad.com/files/george-orwell-on-writing.pdf&quot;&gt;guide to writing&lt;/a&gt; well also applies to error messages.&lt;a href=&quot;#fnref10&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn11&quot;&gt;&lt;p&gt;I’m linking to this blog as an explenation of the n^2 instances problem. I definitely don’t endorse using Overlappable as a solution for it. I’d prefer using &lt;a href=&quot;https://lexi-lambda.github.io/blog/2017/04/28/lifts-for-free-making-mtl-typeclasses-derivable/&quot;&gt;Alexis&lt;/a&gt; method which is very copy paste-able.&lt;a href=&quot;#fnref11&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn12&quot;&gt;&lt;p&gt;I’m linking to this blog as an explenation of the n^2 instances problem. I definitely don’t endorse using Overlappable as a solution for it. I’d prefer using &lt;a href=&quot;https://lexi-lambda.github.io/blog/2017/04/28/lifts-for-free-making-mtl-typeclasses-derivable/&quot;&gt;Alexis&lt;/a&gt; method which is very copy paste-able.&lt;a href=&quot;#fnref12&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>The Nix mutli-monolith machine (NMMM).</title>
    <link href="https://jappieklooster.nl/the-nix-mutli-monolith-machine-nmmm.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2021-07-31:/the-nix-mutli-monolith-machine-nmmm.html</id>
    <published>2021-07-31T15:05:00Z</published>
    <updated>2021-08-01T15:09:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;figure&gt;
&lt;img src=&quot;images/2021/computer-nixos-monolith.png&quot; alt=&quot;a NMMM computer&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;a NMMM computer&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I redid how my services are structured. Instead of running each project on a separate VM, they’re now all running on a dedicated Hetzner machine. This is what I call the nix multi monolith machine (hence forth called NMMM, pronounced like tasting something delicious prefixed with an&lt;/p&gt;</summary>
    <content type="html">&lt;figure&gt;
&lt;img src=&quot;images/2021/computer-nixos-monolith.png&quot; alt=&quot;a NMMM computer&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;a NMMM computer&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I redid how my services are structured. Instead of running each project on a separate VM, they’re now all running on a dedicated Hetzner machine. This is what I call the nix multi monolith machine (hence forth called NMMM, pronounced like tasting something delicious prefixed with an N). There are some really big advantages to the NMMM approach.&lt;/p&gt;
&lt;h2 id=&quot;why-use-a-nmmm&quot;&gt;Why use a NMMM?&lt;/h2&gt;
&lt;p&gt;Setting up NMMM has a couple of advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the NMMM is cheap &lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;the NMMM is simple &lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;the NMMM doesn’t need nixops while benefiting from nix &lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;the NMMM spins out new services fast &lt;a href=&quot;#fn4&quot; class=&quot;footnote-ref&quot; id=&quot;fnref4&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Obviously there are also some disadvantages to this approach, which get answered in the &lt;a href=&quot;#discussion&quot;&gt;discussion section&lt;/a&gt;. But for a typical startup situation, where money is tight and there is no product market fit yet, and time to market is important, I think the NMMM is the best.&lt;/p&gt;
&lt;h2 id=&quot;what-is-nmmm&quot;&gt;What is NMMM&lt;/h2&gt;
&lt;p&gt;The core of the Nix mutli-monolith machine (NMMM) is a dedicated machine. A dedicated machine means no virtualization, in other word it’s bear metal.&lt;/p&gt;
&lt;p&gt;The second major part of this configuration is nix. This means that every piece of software is described in nix files. Just like the configuration of this software. More on that in the &lt;a href=&quot;#nix-config&quot;&gt;nix config&lt;/a&gt; section.&lt;/p&gt;
&lt;p&gt;The third major part is multi-monoliths. Meaning that you can have multiple, unrelated services running on the same machine. This is something different from micro services. &lt;a href=&quot;https://microservices.io/&quot;&gt;Microservices&lt;/a&gt; communicate with each other at some point to provide a consistent frontend. The &lt;a href=&quot;https://microservices.io/&quot;&gt;link&lt;/a&gt; calls this ‘loosly coupled’, or as I liked to call it: They chat with each other. Monoliths on the other hands should &lt;em&gt;not&lt;/em&gt; communicate with each other and are isolated. They have independent frontends and backends. In other words, no chatting between monoliths. They just stand there &lt;a href=&quot;https://www.youtube.com/watch?v=cHWs3c3YNs4&quot;&gt;silent and ominous&lt;/a&gt;. I feel this approach falls inline with the &lt;a href=&quot;https://martinfowler.com/bliki/MonolithFirst.html&quot;&gt;monlith first&lt;/a&gt; approach, but rather then a single monolith I can deploy many completely unrelated projects.&lt;/p&gt;
&lt;h2 id=&quot;nix-config&quot;&gt;&lt;a id=&quot;nix-config&quot;&gt;&lt;/a&gt; Nix config&lt;/h2&gt;
&lt;p&gt;I build this by relying on the &lt;a href=&quot;https://nixos.wiki/wiki/Module&quot;&gt;module system&lt;/a&gt;. The main entrypoint is an ordinary nixos &lt;a href=&quot;https://nixos.org/manual/nixos/stable/index.html#sec-configuration-file&quot;&gt;configuration file&lt;/a&gt;, other modules in general are also shaped like this even though the entry point depends on them. So we got a very versatile one trick pony!&lt;/p&gt;
&lt;p&gt;Assuming &lt;code&gt;/&lt;/code&gt; is the root of the project, the root configuration looks like this:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode nix&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# /nix/hetzner/configuration.nix&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;pkgs&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;:&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;#cb1-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;imports&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;#cb1-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;#cb1-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ss&quot;&gt;./hardware-configuration.nix&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;#cb1-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ss&quot;&gt;../../videocut.org/nix/videocut.nix&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;#cb1-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ss&quot;&gt;../../massapp.org/nix/massapp.nix&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-10&quot;&gt;&lt;a href=&quot;#cb1-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ss&quot;&gt;../../raster.click/nixops/raster.nix&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-11&quot;&gt;&lt;a href=&quot;#cb1-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-12&quot;&gt;&lt;a href=&quot;#cb1-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That has the same structure as the &lt;code&gt;configuration.nix&lt;/code&gt; I use on &lt;a href=&quot;https://github.com/jappeace/linux-config/blob/lenovo-amd/configuration.nix#L35&quot;&gt;my laptop&lt;/a&gt;. The difference this example has with my laptop is that I’m pulling in a bunch of additional modules aside from the hardware config trough the &lt;code&gt;imports&lt;/code&gt; mechanism. &lt;code&gt;imports&lt;/code&gt; tells nixos to also include those other configuration files. However before looking into those specific files, I need to explain how to run this entrypoint. I call this configuration from my &lt;code&gt;/makefile&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;make&quot;&gt;&lt;code&gt;deploy:
	nix-shell nix/nixpkgs-shell.nix --run &amp;quot;make deploy_&amp;quot;

ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))

deploy_:
	NIXOS_CONFIG=&amp;quot;$(ROOT_DIR)/nix/hetzner/configuration.nix&amp;quot; nixos-rebuild switch --target-host root@videocut.org --show-trace&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;make deploy&lt;/code&gt; will deploy if called form the root of the project &lt;code&gt;/&lt;/code&gt;. It runs &lt;code&gt;make deploy_&lt;/code&gt; from a shell that sets the &lt;code&gt;NIX_PATH&lt;/code&gt; to a &lt;a href=&quot;https://jappieklooster.nl/pinning-nixops-builds.html&quot;&gt;pinned nixpkgs&lt;/a&gt;. This uses &lt;code&gt;nixos-rebuild switch&lt;/code&gt;, just like on my laptop. However I specify the target host to be one of the domains hosted on the Hetzner machine. All domains domains lead to the Hetzner machine.&lt;/p&gt;
&lt;p&gt;But how does the machine decide which HTTP request goes to what service? After all they all arrive on the same machine now, so something has to make a decision on this. &lt;a href=&quot;https://www.nginx.com/&quot;&gt;Nginx&lt;/a&gt; can do that! this is a bit later in the entry point file:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode nix&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;co&quot;&gt;# /nix/hetzner/configuration.nix&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;#cb3-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;..&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;#cb3-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  services&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;nginx = &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;#cb3-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;virtualHosts&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;  pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;lib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;foldr &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;prev&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;lib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;recursiveUpdate &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; x&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; prev&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-5&quot;&gt;&lt;a href=&quot;#cb3-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;../../videocut.org/nix/vhost.nix&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-6&quot;&gt;&lt;a href=&quot;#cb3-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;       &lt;span class=&quot;ss&quot;&gt;../../massapp.org/nix/vhost.nix&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-7&quot;&gt;&lt;a href=&quot;#cb3-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;       &lt;span class=&quot;ss&quot;&gt;../../raster.click/nixops/vhost.nix&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-8&quot;&gt;&lt;a href=&quot;#cb3-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;       &lt;span class=&quot;ss&quot;&gt;../../blog/vhost.nix&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-9&quot;&gt;&lt;a href=&quot;#cb3-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-10&quot;&gt;&lt;a href=&quot;#cb3-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;er&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-11&quot;&gt;&lt;a href=&quot;#cb3-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;..&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We let the individual services decide how to configure the virtual hosts. Virtual hosts allow us to specify configurations per &lt;a href=&quot;http://nginx.org/en/docs/http/request_processing.html&quot;&gt;domain name&lt;/a&gt;. For example the &lt;a href=&quot;https://massapp.org/&quot;&gt;massapp.org&lt;/a&gt; host looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  # /massapp.org/nix/vhost.nix
  lib = import ./lib.nix;
  sslBools = {
    forceSSL = true;
    enableACME = true; # E
  };
  base = locations:
    {
      inherit locations;
    } // sslBools; # C
  proxy = base {
    &amp;quot;/&amp;quot;.proxyPass = &amp;quot;http://127.0.0.1:${
        toString lib.massapp_port # D
      }/&amp;quot;; 
  };
  redirect = { globalRedirect = &amp;quot;${lib.massappDomain}&amp;quot;; } // sslBools;
in {
  &amp;quot;www.${lib.massappDomain}&amp;quot; = redirect; # B
  &amp;quot;${lib.massappDomain}&amp;quot; = proxy; # A&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The main thing we’re saying at &lt;code&gt;A&lt;/code&gt; is that the &lt;a href=&quot;https://massapp.org/&quot;&gt;massapp.org&lt;/a&gt; domain should point to the port defined at &lt;code&gt;D&lt;/code&gt;. Furthermore in &lt;code&gt;B&lt;/code&gt; we’re redirecting all &lt;code&gt;www&lt;/code&gt; traffic to &lt;code&gt;A&lt;/code&gt;. Which strips off &lt;code&gt;www&lt;/code&gt; from &lt;code&gt;www.masssapp.org&lt;/code&gt; resulting into &lt;code&gt;massapp.org&lt;/code&gt;. For some reason people still yearn to type &lt;code&gt;www&lt;/code&gt;. With this redirect we trash the peoples’ pointless dreams and desires. Finally in &lt;code&gt;C&lt;/code&gt; we strip of the HTTPS, which the proxy will remake into an HTTP connection. Traffic at this point is internal, so &lt;a href=&quot;http://www.steves-internet-guide.com/ssl-certificates-explained/&quot;&gt;SSL&lt;/a&gt; has served it’s purpose and we can safely strip it. In practice this means our application doesn’t have to deal with certificates or SSL. This leverages nixos &lt;a href=&quot;https://nixos.wiki/wiki/Nginx&quot;&gt;built-in&lt;/a&gt; &lt;a href=&quot;https://letsencrypt.org/&quot;&gt;let’s encrypt&lt;/a&gt; support without even thinking about it in &lt;code&gt;E&lt;/code&gt; &lt;a href=&quot;#fn5&quot; class=&quot;footnote-ref&quot; id=&quot;fnref5&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since we just bound all incoming domains to a unique port, we have to bind a program to that port as well. This program is our main application code, or the monolith. For example let’s look at the massapp module. Herein I register a systemd service which runs the main massapp executable. This is another file like &lt;code&gt;configuration.nix&lt;/code&gt; (just like my laptop! The one trick pony):&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode nix&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# /massapp.org/nix/massapp.nix&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;#cb5-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;pkgs&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;:&lt;/span&gt;
&lt;span id=&quot;cb5-3&quot;&gt;&lt;a href=&quot;#cb5-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-4&quot;&gt;&lt;a href=&quot;#cb5-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;massapp&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;callPackage &lt;span class=&quot;ss&quot;&gt;../webservice/default.nix&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;# A&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-5&quot;&gt;&lt;a href=&quot;#cb5-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-6&quot;&gt;&lt;a href=&quot;#cb5-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-7&quot;&gt;&lt;a href=&quot;#cb5-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;systemd&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;services&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;massapp&lt;/span&gt; = &lt;span class=&quot;co&quot;&gt;# D&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-8&quot;&gt;&lt;a href=&quot;#cb5-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        {&lt;/span&gt;
&lt;span id=&quot;cb5-9&quot;&gt;&lt;a href=&quot;#cb5-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;description&lt;/span&gt; = &amp;quot;&lt;span class=&quot;va&quot;&gt;Massapp&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;webservice&lt;/span&gt;&amp;quot;;&lt;/span&gt;
&lt;span id=&quot;cb5-10&quot;&gt;&lt;a href=&quot;#cb5-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;serviceConfig&lt;/span&gt; = {&lt;/span&gt;
&lt;span id=&quot;cb5-11&quot;&gt;&lt;a href=&quot;#cb5-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;Type&lt;/span&gt; = &amp;quot;&lt;span class=&quot;va&quot;&gt;simple&lt;/span&gt;&amp;quot;;&lt;/span&gt;
&lt;span id=&quot;cb5-12&quot;&gt;&lt;a href=&quot;#cb5-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;ExecStart&lt;/span&gt; = &amp;quot;${ &lt;span class=&quot;va&quot;&gt;massapp&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;/bin/massapp&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;; # B&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-13&quot;&gt;&lt;a href=&quot;#cb5-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;        };&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-14&quot;&gt;&lt;a href=&quot;#cb5-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;        wantedBy = [ &amp;quot;&lt;/span&gt;multi&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;user&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;st&quot;&gt;&amp;quot; ];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-15&quot;&gt;&lt;a href=&quot;#cb5-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;        requires = [ &amp;quot;&lt;/span&gt;postgresql&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;service&lt;span class=&quot;st&quot;&gt;&amp;quot; ];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-16&quot;&gt;&lt;a href=&quot;#cb5-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;        environment = {&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-17&quot;&gt;&lt;a href=&quot;#cb5-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;            PORT = &amp;quot;&lt;/span&gt;$&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;toString&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;lib&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;massapp_port&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;; # C&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-18&quot;&gt;&lt;a href=&quot;#cb5-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;            ...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-19&quot;&gt;&lt;a href=&quot;#cb5-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;        };&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-20&quot;&gt;&lt;a href=&quot;#cb5-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-21&quot;&gt;&lt;a href=&quot;#cb5-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Within &lt;code&gt;A&lt;/code&gt; I load the main binary of the service. We tell systemd about that program at &lt;code&gt;B&lt;/code&gt;. Finally we make the program aware of the correct port in &lt;code&gt;C&lt;/code&gt; by setting the environment variable &lt;code&gt;PORT&lt;/code&gt;. &lt;a href=&quot;https://www.yesodweb.com/&quot;&gt;Yesod&lt;/a&gt; has a configuration built in for that by default, and massapp is a &lt;a href=&quot;https://www.yesodweb.com/&quot;&gt;Yesod&lt;/a&gt; application. This would work for any other application, you can even pass CLI arguments like this just by modifying the &lt;code&gt;ExecStart&lt;/code&gt;. At &lt;code&gt;D&lt;/code&gt; we give this systemd unit the name massapp, by doing this std out is logged in journalctl and tagged with the unit name. Nixos-rebuild will now also know if a service failed trough exit codes. For example if the service can’t find the database. Which we discuss how to setup in the &lt;a href=&quot;#database&quot;&gt;database&lt;/a&gt; section.&lt;/p&gt;
&lt;h2 id=&quot;database-integration&quot;&gt;&lt;a id=&quot;database&quot;&gt;&lt;/a&gt; Database integration&lt;/h2&gt;
&lt;p&gt;This is the database configuration, again in the entrypoint &lt;code&gt;configuration.nix&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode nix&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;#cb6-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;co&quot;&gt;# /nix/hetzner/configuration.nix&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;#cb6-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;..&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;#cb6-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  services&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;postgresql = &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;#cb6-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;#cb6-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;co&quot;&gt;# A&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-6&quot;&gt;&lt;a href=&quot;#cb6-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;authentication&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;lib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;mkOverride &lt;span class=&quot;dv&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-7&quot;&gt;&lt;a href=&quot;#cb6-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;      local all all trust&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-8&quot;&gt;&lt;a href=&quot;#cb6-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;      host all all ::1/128 trust&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-9&quot;&gt;&lt;a href=&quot;#cb6-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;      host all all 0.0.0.0/0 md5&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-10&quot;&gt;&lt;a href=&quot;#cb6-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;      host all all ::/0       md5&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-11&quot;&gt;&lt;a href=&quot;#cb6-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;    &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-12&quot;&gt;&lt;a href=&quot;#cb6-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;settings&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;  &lt;span class=&quot;co&quot;&gt;# B&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-13&quot;&gt;&lt;a href=&quot;#cb6-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;log_connections&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;yes&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-14&quot;&gt;&lt;a href=&quot;#cb6-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;log_statement&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;all&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-15&quot;&gt;&lt;a href=&quot;#cb6-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;log_disconnections&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;yes&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-16&quot;&gt;&lt;a href=&quot;#cb6-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-17&quot;&gt;&lt;a href=&quot;#cb6-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-18&quot;&gt;&lt;a href=&quot;#cb6-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;co&quot;&gt;# C&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-19&quot;&gt;&lt;a href=&quot;#cb6-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;initialScript&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;writeText &lt;span class=&quot;st&quot;&gt;&amp;quot;backend-initScript&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-20&quot;&gt;&lt;a href=&quot;#cb6-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;      CREATE USER massapp_prod WITH PASSWORD &amp;#39;someinitialpassword&amp;#39;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-21&quot;&gt;&lt;a href=&quot;#cb6-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;      CREATE DATABASE massapp_prod;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-22&quot;&gt;&lt;a href=&quot;#cb6-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;      ALTER USER massapp_prod WITH SUPERUSER;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-23&quot;&gt;&lt;a href=&quot;#cb6-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;      &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-24&quot;&gt;&lt;a href=&quot;#cb6-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   ...&lt;/span&gt;
&lt;span id=&quot;cb6-25&quot;&gt;&lt;a href=&quot;#cb6-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The initial script&lt;code&gt;C&lt;/code&gt; is only run when the database is started for the first time, after that you need to manage users by hand. However I still add these users to script to keep track of them if I ever need to abandon this system. Like this at least the users will exist on the new machine. I give every monoliths’ user superuser access in &lt;code&gt;C&lt;/code&gt;. This isn’t the best for security, but it’s really convenient. Besides if a hacker manages to get a shell for the system or a shell for the database it’s already to late for me anyway. I’d just scrap this system and start over elsewhere.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;B&lt;/code&gt; I set some additional logging options, which are just convenient when things break&lt;a href=&quot;#fn6&quot; class=&quot;footnote-ref&quot; id=&quot;fnref6&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;6&lt;/sup&gt;&lt;/a&gt;. With statement logging I can still see what happened in the database if the application didn’t emit enough information. logging all statements &lt;a href=&quot;https://dba.stackexchange.com/questions/30144/performance-impact-of-setting-postgresql-to-log-all-statements&quot;&gt;slows down&lt;/a&gt; the database. However, my services are hardly taxed at the moment, they are taxed but no where near justifying not logging.&lt;/p&gt;
&lt;p&gt;Localhost connections can authenticate without password in &lt;code&gt;A&lt;/code&gt;. Outside connections are ignored, they’re not even asked for a password.&lt;/p&gt;
&lt;h2 id=&quot;discussion&quot;&gt;&lt;a id=&quot;discussion&quot;&gt;&lt;/a&gt; Discussion&lt;/h2&gt;
&lt;p&gt;This setup goes against &lt;a href=&quot;https://www.reddit.com/r/sysadmin/comments/92qhuu/should_i_put_multiple_services_on_a_single_vm_or/&quot;&gt;advice&lt;/a&gt; from sysadmins, where they recommend you split up everything across VM’s as much as possible. I reject &lt;a href=&quot;https://www.youtube.com/watch?v=nyErR1FS1_0&quot;&gt;their hypothesis&lt;/a&gt;. I mean they argue for splitting services, but the tool used for splitting shouldn’t be dogmatic and always result in choosing a VM. Using multiprocessing, and tenanting for specific software packages is good enough. &lt;a href=&quot;https://www.reddit.com/r/sysadmin/comments/92qhuu/should_i_put_multiple_services_on_a_single_vm_or/e37r7pm/&quot;&gt;myron semacks&lt;/a&gt; at least gives some arguments on why he chooses to use a VM. However his reasons for choosing a VM’s revolve around windows related oddities. For example:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Think about what happens when you need to upgrade the OS, which typically means you make a new VM to replace the old one.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We can seamlessly upgrade nixos pretty much always. I’ve had configuration files change which caused errors when upgrading nixos stable versions, but these errors need to be solved before deploying. The systems I use with nixos themselves have always been stable. Or:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Think about what happens when there is a problem and the VM is down. (Bad Windows update, you fat fingered a network setting, etc)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;How would I even fat finger a network setting? I have to modify a file, commit the file and deploy to do this. At this point you can’t even call it fat fingering. And even if you somehow screw up a network setting deliberately, you can reboot from an older generation and the problem is gone. The difference here is that this deployment is nix based, which allows me to manage the complexity of the monolith much more efficiently and reliably.&lt;/p&gt;
&lt;p&gt;NMMM can also be used to impress potential clients by quickly creating new websites. What are the steps?&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;Get the new domain, for example &lt;code&gt;newdomain.com&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;copy over the &lt;code&gt;massapp.org&lt;/code&gt; folder into &lt;code&gt;newdomain.com&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;hook it into the main config&lt;code&gt;/nix/hetzner/configuration.nix&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;setup the database,&lt;/li&gt;
&lt;li&gt;redo branding&lt;/li&gt;
&lt;li&gt;deploy.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That’s it. That’s two hours of work, maybe three if something goes wrong. Nothing is more impressive then have a functioning website, &lt;em&gt;the next day&lt;/em&gt;. I guess aside from startups, consultancies should also look into this approach.&lt;/p&gt;
&lt;p&gt;On several occasions I’ve mentioned that &lt;code&gt;configuration.nix&lt;/code&gt; is just like on my laptop. Originally I even copied pasted the Postgres configuration from my laptop to this machine. It just works. This is one of the big benefits you get out of nix, it’s called the &lt;a href=&quot;https://www.youtube.com/watch?v=OyfBQmvr2Hc&amp;amp;t=2305s&quot;&gt;copy-paste monad&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you’re having doubts about nixops and want to replace it, you may run into secret management issues. Fortunately there is an alternative project for secret management called &lt;a href=&quot;https://github.com/ryantm/agenix&quot;&gt;agenix&lt;/a&gt;. Although I’m a bit skeptical over &lt;a href=&quot;https://github.com/FiloSottile/age&quot;&gt;age&lt;/a&gt;, it seems to new to trust. You should do your diligence before using that in production.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I described this NMMM setup that’s working really well for me. Furthermore I think I gave compelling reasons for others to try this out. Perhaps I liberated some people from their &lt;a href=&quot;https://www.youtube.com/watch?v=4JkIs37a2JE&quot;&gt;virtual insanity&lt;/a&gt;. Let me know if I’ve inspired you to change your course of action, or you’ve some compelling reasons not to use this approach. Because how to structure services is a large decision, I find this all fascinating.&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;Further reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nixos.org/manual/nixos/stable/index.html#sec-configuration-file&quot;&gt;The NixOS configuration file explained&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nixos.wiki/wiki/Module&quot;&gt;NixOS module system&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/nh2/ebc27311731f53ee623ae781ca25103f&quot;&gt;Setting up a Hetzner machine with NixOS script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;General nix advice:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nix.dev/&quot;&gt;nix.dev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nixos.org/guides/nix-pills/&quot;&gt;nix ‘pills’&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;The price of a &lt;a href=&quot;https://www.hetzner.com/dedicated-rootserver&quot;&gt;Hetzner&lt;/a&gt; machine is &lt;code&gt;€ 45&lt;/code&gt; euro’s per month. This gives you 1 terabyte of raid-1 disks, 12 threads and 64g of ram. You &lt;a href=&quot;https://aws.amazon.com/blogs/aws/new-t3-instances-burstable-cost-effective-performance/&quot;&gt;currently&lt;/a&gt; pay around &lt;code&gt;$ 240&lt;/code&gt; dollar per month for a t3.2xlarge instance. That’s halve the amount of ram and only 8 vCPU’s (not dedicated threads) and that doesn’t include network cost or storage. It’s safe to say that Hetzner is &lt;em&gt;cheap&lt;/em&gt;.
&lt;p&gt;
Of course on AWS you can get a much smaller machine for a cheaper price per month, which may sound good initially, but as soon as you need larger or more machines, a dedicated machine become much more cost effective. And you’ll need a larger machine eventually. If your idea fails you probably want to keep it online for your resume, which would make it one of the monoliths, or it succeeds and you need a bigger machine to deal with memory volatility. I happened to need a large machine to do video editing for &lt;a href=&quot;https://videocut.org/&quot;&gt;videocut.org&lt;/a&gt;.
&lt;/p&gt;
&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;The setup is simple because you don’t have to do networking. Everything is on the same machine, which means you only have to do inter process communication. Furthermore, all services communicate to the same database process, which uses the databases’ internal tenanting system to ensure the data remains isolated.
&lt;p&gt;
The same goes for anything else services need, if a service needs the filesystem, just prefix some folder with their domain name. I don’t have to deal with buckets or networking issues. and if something doesn’t work, 9 out of 10 times systemd will tell me exactly what’s broken, no need to dive into the AWS CLI.
&lt;/p&gt;
&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;For me nixops causes a lot of needles friction which I like to avoid. For example, the nixops developers decided to change how the CLI works from the bash based counterparts. &lt;code&gt;nixops scp&lt;/code&gt; only works with &lt;code&gt;--from&lt;/code&gt; and &lt;code&gt;--to&lt;/code&gt; flags. It refuses to accept the ordinary scp syntax, for no reason.
&lt;p&gt;
There are countless other examples of this kind of friction. I just get frustrated by writing about it, so I won’t. However the more important thing this does is to cut out one of the variables during deployment. I can cut out both Nixops and the AWS variables, after all I don’t need to manage AWS, so why would I use nixops?
&lt;/p&gt;
&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;Finally the last advantage is that setting up a new service is &lt;em&gt;fast&lt;/em&gt;. No need to wait ages for an instance to boot, starting a process is nearly instant after all. This is sort off the same as &lt;code&gt;3&lt;/code&gt;, but in this case we’re saying AWS is slow, rather then nixops having poor UX.&lt;a href=&quot;#fnref4&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn5&quot;&gt;&lt;p&gt;It’s built in but this used to break quite a lot, this is because it’s enterly reliant on the graces of let’s encrypt service. Which may refuse you to give a certificate for all &lt;a href=&quot;https://letsencrypt.org/docs/rate-limits/&quot;&gt;kinds of reasons&lt;/a&gt;.&lt;a href=&quot;#fnref5&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn6&quot;&gt;&lt;p&gt;When do things break you ask? Well of course all software is broken so we always need to enable this.&lt;a href=&quot;#fnref6&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Using git for templates</title>
    <link href="https://jappieklooster.nl/using-git-for-templates.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2020-10-24:/using-git-for-templates.html</id>
    <published>2020-10-24T15:00:00Z</published>
    <updated>2020-10-24T15:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;Over the past few years I’ve started using git as a template management tool&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;. For example, I clone my &lt;a href=&quot;https://github.com/jappeace/haskell-template-project&quot;&gt;haskell template project&lt;/a&gt;, edit the names, edit the &lt;code&gt;readme&lt;/code&gt; end re-setup the remotes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git remote add template git@github.com:jappeace/haskell-template-project.git
git remote set-url origin git@github.com:jappeace/new-project.git&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This allows me to keep&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Over the past few years I’ve started using git as a template management tool&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;. For example, I clone my &lt;a href=&quot;https://github.com/jappeace/haskell-template-project&quot;&gt;haskell template project&lt;/a&gt;, edit the names, edit the &lt;code&gt;readme&lt;/code&gt; end re-setup the remotes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git remote add template git@github.com:jappeace/haskell-template-project.git
git remote set-url origin git@github.com:jappeace/new-project.git&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This allows me to keep my downstream project up to date with the template. When I discover another tool, this can be merged into the downstream project for example. It allows evolving the template over time as I learn more about whatever programming language I’m using.&lt;/p&gt;
&lt;p&gt;It also gives me default branding. Which makes it look more ‘professional’. Although I don’t like branding, I know this is necessary. Having it there by default makes it so that I don’t forget to do this.&lt;/p&gt;
&lt;p&gt;When starting a project you also gain some free authoritativeness, because you have a longer commit history the project looks like it is more mature. Although this practice is a little deceptive, there is a core of truth, because the template has gotten a lot of attention. If you feel offended by this practice, ask yourself first, why are you trusting git histories? These can be &lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History&quot;&gt;rewritten anyway&lt;/a&gt;. This authoritativeness also gives me a small moral boost. It just &lt;em&gt;feels&lt;/em&gt; better to have a project with well thought out tools being started and some history rather then the ‘normal’ stuff everyone starts with.&lt;/p&gt;
&lt;h2 id=&quot;alternatives&quot;&gt;Alternatives&lt;/h2&gt;
&lt;p&gt;The alternatives are using tools that spit out templates. In the haskell world these are &lt;a href=&quot;https://github.com/commercialhaskell/stack-templates&quot;&gt;stack new&lt;/a&gt;, &lt;a href=&quot;https://cabal.readthedocs.io/en/latest/developing-packages.html#using-cabal-init&quot;&gt;cabal init&lt;/a&gt; or &lt;a href=&quot;https://github.com/kowainik/summoner&quot;&gt;summoner&lt;/a&gt;. These tools are simply a glorified &lt;code&gt;sed&lt;/code&gt; on projects folders: They find and replace variables. There is no versioning, there is no personalization except what limited variables give.&lt;/p&gt;
&lt;p&gt;Because these tools don’t take into account history, the first commit will be a large commit with a message like ‘Initial’. I find this problematic because it squashes all the work that went into creating the template. Information is lost, for no reason.&lt;/p&gt;
&lt;!-- TODO verify this--&gt;
&lt;p&gt;These tools don’t use git to track their templates. They could, but they don’t. Maybe they wanted to be VCS&lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; agnostic? I’m speculating, but even if you wanted to be that, you could still use any version system to track the template and recreate the history in the VCS desired by the user. This at least gives the user their history of the template back. While also giving them the choice of VCS&lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-template-hierarchy&quot;&gt;A template hierarchy&lt;/h2&gt;
&lt;p&gt;What I described in the intro can be taken a step further. A template of a template can be used to create another new template. For example, say you’re a fan of &lt;a href=&quot;https://nixos.org/&quot;&gt;nix&lt;/a&gt; or &lt;a href=&quot;https://www.gnu.org/software/make/manual/make.html&quot;&gt;make&lt;/a&gt;, so why not put a makefile and a &lt;a href=&quot;https://nix.dev/tutorials/towards-reproducibility-pinning-nixpkgs.html#pinning-nixpkgs&quot;&gt;nix pin&lt;/a&gt; in some template of templates project. These tools don’t care about which language you use, so their configuration can be shared among Python, Java and Haskell projects for example. Maybe for github it could even have a partial travis or github actions CI setup.&lt;/p&gt;
&lt;p&gt;Now, say you’re starting a new Python project, but have no template yet for that programming language. You simply clone this template of templates and customize it to your own &lt;a href=&quot;https://stackoverflow.com/questions/25011078/what-does-pythonic-mean#:~:text=Pythonic%20means%20code%20that%20doesn,is%20intended%20to%20be%20used.&quot;&gt;Pythonic&lt;/a&gt; needs. You can still pull in the upstream changes from your template of templates, for example to upgrade the nix pin. The big advantage of course is that a change in the template of templates can easily merged into all downstream projects with git.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;I convinced the reader that using git is the superior way for template management. It’s simpler, and more flexible. I also convinced the authors of stack, cabal and summoner to drop their current way of managing templates and use git instead.&lt;/p&gt;
&lt;p&gt;Or, more likely, no-one read this far.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;This started out as having no better alternative, due to my nixos choice. But now I realise, this is the best alternative.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;Version Control System&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;I wouldn’t bother with this choice unless someone is asking for it. I think git has won the VCS battle by a wide &lt;a href=&quot;https://softwareengineering.stackexchange.com/questions/136079/are-there-any-statistics-that-show-the-popularity-of-git-versus-svn&quot;&gt;margin&lt;/a&gt;. Of course that’s easy for me the say as neither maintainer nor user. 25% SVN market share is a lot more then I expected (the absolute SVN repo count is still going up!).&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Hacking atom</title>
    <link href="https://jappieklooster.nl/hacking-atom.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2020-08-16:/hacking-atom.html</id>
    <published>2020-08-16T21:12:00Z</published>
    <updated>2020-08-16T23:09:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;On my &lt;a href=&quot;https://www.twitch.tv/jappiejappie&quot;&gt;twitch stream&lt;/a&gt; I had project where I made a &lt;a href=&quot;https://en.wikipedia.org/wiki/Scan_line&quot;&gt;CRT scan line&lt;/a&gt; monitor in atom:&lt;/p&gt;
&lt;iframe class=&quot;video&quot; src=&quot;https://www.youtube.com/embed/FdYISkTBVuw&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;
&lt;/iframe&gt;
&lt;p&gt;The inspiration was the fallout &lt;a href=&quot;https://fallout.fandom.com/wiki/Pip-Boy&quot;&gt;pip-boy&lt;/a&gt;. I though it would be cool to have this be in your editor, maybe some of the gray beards are nostalgic for this?&lt;/p&gt;
&lt;p&gt;What amazes me&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;On my &lt;a href=&quot;https://www.twitch.tv/jappiejappie&quot;&gt;twitch stream&lt;/a&gt; I had project where I made a &lt;a href=&quot;https://en.wikipedia.org/wiki/Scan_line&quot;&gt;CRT scan line&lt;/a&gt; monitor in atom:&lt;/p&gt;
&lt;iframe class=&quot;video&quot; src=&quot;https://www.youtube.com/embed/FdYISkTBVuw&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;
&lt;/iframe&gt;
&lt;p&gt;The inspiration was the fallout &lt;a href=&quot;https://fallout.fandom.com/wiki/Pip-Boy&quot;&gt;pip-boy&lt;/a&gt;. I though it would be cool to have this be in your editor, maybe some of the gray beards are nostalgic for this?&lt;/p&gt;
&lt;p&gt;What amazes me is that this is possible with just CSS. Atom has become my favorite editor after doing this project (although I hardly use it), and my love for CSS has grown even more!&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Ghcid for multi package projects</title>
    <link href="https://jappieklooster.nl/ghcid-for-multi-package-projects.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2019-10-17:/ghcid-for-multi-package-projects.html</id>
    <published>2019-10-17T21:30:00Z</published>
    <updated>2019-12-13T21:58:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;figure&gt;
&lt;img src=&quot;/images/2019/fire.svg&quot; alt=&quot;GHCID magic&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;GHCID magic&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;When I tried &lt;a href=&quot;https://github.com/ndmitchell/ghcid&quot;&gt;Ghcid&lt;/a&gt;for a &lt;a href=&quot;http://hackage.haskell.org/package/reflex&quot;&gt;reflex&lt;/a&gt; project, it wouldn’t rebuild on file change. This is because reflex has a multi package project setup by default. Recently I found that it is possible to use &lt;a href=&quot;https://github.com/ndmitchell/Ghcid&quot;&gt;Ghcid&lt;/a&gt; for multi package project builds. The trick is to create an executable&lt;/p&gt;</summary>
    <content type="html">&lt;figure&gt;
&lt;img src=&quot;/images/2019/fire.svg&quot; alt=&quot;GHCID magic&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;GHCID magic&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;When I tried &lt;a href=&quot;https://github.com/ndmitchell/ghcid&quot;&gt;Ghcid&lt;/a&gt;for a &lt;a href=&quot;http://hackage.haskell.org/package/reflex&quot;&gt;reflex&lt;/a&gt; project, it wouldn’t rebuild on file change. This is because reflex has a multi package project setup by default. Recently I found that it is possible to use &lt;a href=&quot;https://github.com/ndmitchell/Ghcid&quot;&gt;Ghcid&lt;/a&gt; for multi package project builds. The trick is to create an executable that includes all the sources. For example in &lt;a href=&quot;https://github.com/sol/hpack&quot;&gt;hpack&lt;/a&gt; style:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;tests&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;unit&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt;                Spec.hs&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;source-dirs&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;#cb1-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; test&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;#cb1-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;    # including extra source dirs allows Ghcid to watch&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;#cb1-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; src &lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;#cb1-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; ../common/src&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;#cb1-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; ../frontend/src&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now Ghcid will watch all the sources. By targeting the test suite you can also immediately use this to run unit tests. If your other project use additional dependencies you may need to add them to that test as well.&lt;/p&gt;
&lt;p&gt;However because I’m doing reflex, I had to compile JavaScript after Ghcid typed checked everything. I also had some unit tests to run. Luckily Ghcid supports both a run and a test flag. I simply used the &lt;code&gt;run&lt;/code&gt; flag to run the tests and the &lt;code&gt;test&lt;/code&gt; flag to start GHCJS compilation. Which brings us to this spell:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ex&quot;&gt;ghcid&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;import Main&amp;quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;at&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;make update-cabal &amp;amp;&amp;amp; cabal new-repl&amp;quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;#cb2-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;at&quot;&gt;-T&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;:! cd .. &amp;amp;&amp;amp; make after-native-build&amp;quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;#cb2-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;at&quot;&gt;--run&lt;/span&gt; test:unit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The run flag can also be used to run your code if you don’t have a weird GHCJS requirement like me. Running like that gives fast feedback because it’s interpreted.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;This setup is an order of magnitude faster for debugging in my case. If I have a compile error it now notifies me instantaneously, whereas before it would take a second or two. If I need to do a full build it takes about 10 seconds, whereas before it was somewhere around a minute or two.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Pinning nixops builds</title>
    <link href="https://jappieklooster.nl/pinning-nixops-builds.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2019-10-17:/pinning-nixops-builds.html</id>
    <published>2019-10-17T17:35:00Z</published>
    <updated>2019-11-25T23:10:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;figure&gt;
&lt;img src=&quot;/images/2019/pinned-nixos.png&quot; alt=&quot;Pinned nixops&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Pinned nixops&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;On one machine my &lt;a href=&quot;https://nixos.org/nixops/&quot;&gt;Nixops&lt;/a&gt; builds and deploys, but on the other one it fails. Why? Isn’t nix supposed to deliver &lt;a href=&quot;https://www.software.ac.uk/blog/2017-10-05-reproducible-environments-nix&quot;&gt;reproducible builds&lt;/a&gt;? Turns out nixops uses by default your system configurations’ &lt;a href=&quot;https://github.com/NixOS/nixops/issues/736#issuecomment-333399151&quot;&gt;channels&lt;/a&gt; rather then a &lt;a href=&quot;https://vaibhavsagar.com/blog/2018/05/27/quick-easy-nixpkgs-pinning/&quot;&gt;pinned nix packages&lt;/a&gt;. Which is not &lt;a href=&quot;https://medium.com/@ejpcmac/about-using-nix-in-my-development-workflow-12422a1f2f4c&quot;&gt;why you’re using nix&lt;/a&gt;&lt;/p&gt;</summary>
    <content type="html">&lt;figure&gt;
&lt;img src=&quot;/images/2019/pinned-nixos.png&quot; alt=&quot;Pinned nixops&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Pinned nixops&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;On one machine my &lt;a href=&quot;https://nixos.org/nixops/&quot;&gt;Nixops&lt;/a&gt; builds and deploys, but on the other one it fails. Why? Isn’t nix supposed to deliver &lt;a href=&quot;https://www.software.ac.uk/blog/2017-10-05-reproducible-environments-nix&quot;&gt;reproducible builds&lt;/a&gt;? Turns out nixops uses by default your system configurations’ &lt;a href=&quot;https://github.com/NixOS/nixops/issues/736#issuecomment-333399151&quot;&gt;channels&lt;/a&gt; rather then a &lt;a href=&quot;https://vaibhavsagar.com/blog/2018/05/27/quick-easy-nixpkgs-pinning/&quot;&gt;pinned nix packages&lt;/a&gt;. Which is not &lt;a href=&quot;https://medium.com/@ejpcmac/about-using-nix-in-my-development-workflow-12422a1f2f4c&quot;&gt;why you’re using nix&lt;/a&gt;. You want a reproducible build, in other words, either both machines fail for the same reason or both succeed. We will discuss how to do this for nixops in this post trough a pin.&lt;/p&gt;
&lt;p&gt;To pin a nixops deployment we create a shell[^alternative] from which we run nixops: [^alternative]: For my reflex project I simply made an alternative shell, because reflex-platform doesn’t make the shell easily modifiable. you can run a different shell by providing the filename to the nix-shell command: &lt;code&gt;nix-shell nixops-shell.nix&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode nix&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;va&quot;&gt;pkgs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;./pin.nix&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;#cb1-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;stdenv&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;mkDerivation&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;#cb1-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;nixops-env&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;#cb1-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;NIX_PATH&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;nixpkgs=&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;${&lt;/span&gt;pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;path&lt;span class=&quot;sc&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;#cb1-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;buildInputs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;nixops &lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;#cb1-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Where &lt;code&gt;pin.nix&lt;/code&gt; &lt;a href=&quot;https://nixos.wiki/wiki/FAQ/Pinning_Nixpkgs&quot;&gt;looks like&lt;/a&gt; this:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode nix&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;va&quot;&gt;hostPkgs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; &amp;lt;nixpkgs&amp;gt; &lt;span class=&quot;op&quot;&gt;{};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;#cb2-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;va&quot;&gt;pinnedPkgs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; hostPkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;fetchFromGitHub &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;#cb2-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;owner&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;NixOS&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;#cb2-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;repo&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;nixpkgs-channels&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;#cb2-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;rev&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;1601f559e89ba71091faa26888711d4dd24c2d4d&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;#cb2-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;sha256&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;0iayyz9617mz6424spwbi9qvmcl8hiql42czxg8mi4ycq4p1k0dx&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-8&quot;&gt;&lt;a href=&quot;#cb2-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-9&quot;&gt;&lt;a href=&quot;#cb2-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-10&quot;&gt;&lt;a href=&quot;#cb2-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; pinnedPkgs &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-11&quot;&gt;&lt;a href=&quot;#cb2-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;config&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;allowUnfree&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;# took me too long to figure out&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-12&quot;&gt;&lt;a href=&quot;#cb2-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is also possible for &lt;a href=&quot;https://github.com/reflex-frp/reflex-platform&quot;&gt;reflex-platform&lt;/a&gt; projects where we simply depend on the provided pin:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode nix&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   pkgs = &lt;span class=&quot;op&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;./reflex&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;}).&lt;/span&gt;nixpkgs;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;In this post we discussed how to pin nixops builds. There are other ways to do pinning, which is described &lt;a href=&quot;https://discourse.nixos.org/t/nixops-pinning-nixpkgs/734&quot;&gt;here&lt;/a&gt;. I found it hard to get a working solution from that thread, therefore I recorded my own solution here.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Reflex server side html rendering</title>
    <link href="https://jappieklooster.nl/reflex-server-side-html-rendering.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2019-08-05:/reflex-server-side-html-rendering.html</id>
    <published>2019-08-05T19:05:00Z</published>
    <updated>2019-08-05T19:05:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;&lt;a href=&quot;%7Bfilename%7D/fullstack-haskell-reflex-servant.md&quot;&gt;Reflex&lt;/a&gt; is a single page app framework written in Haskell compiled to JavaScript. A major concern with reflex is the slow loading times, this can be mediated however by doing server side rendering&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;. This blog post will discuss how to do that&lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2019/bob-busy.jpeg&quot; alt=&quot;Bob doing SSR&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Bob doing SSR&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;%7Bfilename%7D/fullstack-haskell-reflex-servant.md&quot;&gt;Reflex&lt;/a&gt; is a single page app framework written in Haskell compiled to JavaScript. A major concern with reflex is the slow loading times, this can be mediated however by doing server side rendering&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;. This blog post will discuss how to do that&lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2019/bob-busy.jpeg&quot; alt=&quot;Bob doing SSR&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Bob doing SSR&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The main idea is that we can share most of our single page app code on both the frontend as well as the backend. The backend will create a static HTML page, whereas the frontend will be a JavaScript client. The browser can display this HTML content very fast without having to interpret any JavaScript. This is where all the speed gain comes from. &lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; JavaScript developers call this technique &lt;a href=&quot;https://medium.com/capital-one-tech/why-everyone-is-talking-about-isomorphic-universal-JavaScript-and-why-it-matters-38c07c87905&quot;&gt;‘isomporhic’&lt;/a&gt;&lt;a href=&quot;#fn4&quot; class=&quot;footnote-ref&quot; id=&quot;fnref4&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; JavaScript. This blogpost will tell you how to do it with reflex. I found it surprisingly easy, and the results very impressive.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://hackage.haskell.org/package/reflex-dom-core-0.5/docs/Reflex-Dom-Builder-Static.html#v:renderStatic&quot;&gt;renderStatic&lt;/a&gt; function does the HTML rendering. However to use it we need to jump trough some oddly-shaped, &lt;a href=&quot;http://hackage.haskell.org/package/mtl&quot;&gt;MTL&lt;/a&gt; flavoured, hoops&lt;a href=&quot;#fn5&quot; class=&quot;footnote-ref&quot; id=&quot;fnref5&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt;. Doing this is not much harder than writing a regular reflex app. Jumping trough these solves handling browser native primitives, such as XHR calls. This is done with help of &lt;a href=&quot;https://hackage.haskell.org/package/reflex-dom-core-0.5/docs/Reflex-Dom-Prerender.html#v:prerender&quot;&gt;prerender&lt;/a&gt;. Which is also the key to displaying authenticated content fast, but we have to rewire the the initial app state to do that. Fortunately this rewiring caused the initial state management to become more elegant then it was in the &lt;a href=&quot;https://jappieklooster.nl/authentication-in-reflex-servant.html&quot;&gt;authentication&lt;/a&gt; post.&lt;/p&gt;
&lt;p&gt;The source code is available in the &lt;a href=&quot;https://github.com/jappeace/awesome-project-name/tree/prerender&quot;&gt;reference project&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;strange-mtl-hoops&quot;&gt;Strange MTL Hoops&lt;/h1&gt;
&lt;p&gt;We need to get rid of &lt;a href=&quot;https://hackage.haskell.org/package/reflex-dom-core-0.5/docs/src/Reflex.Dom.Old.html#MonadWidgetConstraints&quot;&gt;WidgetMonad&lt;/a&gt; and replace it with the underlying builders. We do this because the WidgetMonad has a nasty equality constraint on GhcjsDomSpace that prevents the use of &lt;code&gt;renderStatic&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadWidgetConstraints&lt;/span&gt; t m &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ( &lt;span class=&quot;dt&quot;&gt;DomBuilder&lt;/span&gt; t m&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  , &lt;span class=&quot;dt&quot;&gt;DomBuilderSpace&lt;/span&gt; m &lt;span class=&quot;op&quot;&gt;~&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;GhcjsDomSpace&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- &amp;lt;-- nasty constraint&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;#cb1-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  )&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;#cb1-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;#cb1-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadWidgetConstraints&lt;/span&gt; t m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;#cb1-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadWidgetConstraints&lt;/span&gt; t m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A good strategy is replacing it with &lt;a href=&quot;http://hackage.haskell.org/package/reflex-dom-core-0.5/docs/Reflex-Dom-Builder-Class.html#t:DomBuilder&quot;&gt;DomBuilder&lt;/a&gt; and add more constraints based on compiler requests. MTL monads push outwards. That is to say, the low level widgets determine the constraints of the higher level widgets.&lt;/p&gt;
&lt;p&gt;Unfortunately this is not the only place for that equality constraint. The input and textarea widgets indirectly cause this constraint too because of their return types. For example in input:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TextInput&lt;/span&gt; t&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TextInput&lt;/span&gt; { &lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;#cb2-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;		&lt;span class=&quot;op&quot;&gt;...&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;#cb2-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;		, _textInput_builderElement &lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;#cb2-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;		::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;InputElement&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EventResult&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;GhcjsDomSpace&lt;/span&gt; t  &lt;span class=&quot;co&quot;&gt;-- &amp;lt;-- nasty fundep&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;#cb2-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;		}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There is no direct equality constraint, but it gets asserted anyway because of &lt;a href=&quot;https://wiki.haskell.org/Functional_dependencies&quot;&gt;functional dependencies&lt;/a&gt;. However I made an alternative to both these widgets in the Bulmex library. In which I just copied the &lt;a href=&quot;https://hackage.haskell.org/package/reflex-dom-core-0.5/docs/Reflex-Dom-Widget-Input.html&quot;&gt;original&lt;/a&gt; and removed the constraining records from the result types. They can be found &lt;a href=&quot;https://hackage.haskell.org/package/bulmex-2.0.0/docs/Reflex-Bulmex-Input-Polymorphic.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;prerender-parts&quot;&gt;Prerender Parts&lt;/h1&gt;
&lt;p&gt;As mentioned before, we intent to share most code between the client and the server. In case of the client we use a JavaScript executable entry point and get a GHCJS DOM environment. In case of the server we use a servant endpoint as entry point and get a static DOM builder environment. When the GHCJS environment is accessed reflex needs to know what to do in the other environment and vice versa. In the browser for example we’ll happily do XHR calls, but when doing server side rendering we can simply ignore the request&lt;a href=&quot;#fn6&quot; class=&quot;footnote-ref&quot; id=&quot;fnref6&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;6&lt;/sup&gt;&lt;/a&gt;. This use case between environments is handled by &lt;a href=&quot;https://hackage.haskell.org/package/reflex-dom-core-0.5/docs/Reflex-Dom-Prerender.html&quot;&gt;prerender&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;prerender ::&lt;/span&gt; m a&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;#cb3-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PrerenderClientConstraint&lt;/span&gt; js t (&lt;span class=&quot;dt&quot;&gt;Client&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Client&lt;/span&gt; m a)&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;#cb3-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t a) &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Depending on the entry point we use we get a different monad environment. On the server we get a StaticDomBuilder environment (&lt;code&gt;m a&lt;/code&gt;), and in the JavaScript executable frontend we get a GHCJS DOM environment (&lt;code&gt;Client m a&lt;/code&gt;). The first monad is the one being displayed on the server, the second one has access to the GHCJS DOM environment. The resulting value will be captured in a dynamic and can be used by the shared code.&lt;/p&gt;
&lt;p&gt;Now we can enhance all servant-reflex calls with prerender calls, to make it do nothing in the static environment and do the XHR calls on the GHCJS dom environment. For example the &lt;code&gt;postLogin&lt;/code&gt; function from the &lt;a href=&quot;https://jappieklooster.nl/authentication-in-reflex-servant.html&quot;&gt;authentication blogpost&lt;/a&gt; now looks like:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;#cb4-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;postLogin ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;DomBuilder&lt;/span&gt; t m, &lt;span class=&quot;dt&quot;&gt;Prerender&lt;/span&gt; js t m)&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;#cb4-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text.Text&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;#cb4-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t ()&lt;/span&gt;
&lt;span id=&quot;cb4-4&quot;&gt;&lt;a href=&quot;#cb4-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;ReqResult&lt;/span&gt; () (&lt;span class=&quot;dt&quot;&gt;AuthCookies&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NoContent&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb4-5&quot;&gt;&lt;a href=&quot;#cb4-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;postLogin dd yy &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; switchDyn &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; prerender (&lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; never) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; postLogin&amp;#39; dd yy&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here &lt;code&gt;postLogin&apos;&lt;/code&gt; is the generated endpoint from &lt;a href=&quot;https://hackage.haskell.org/package/servant-reflex&quot;&gt;servant-reflex&lt;/a&gt;. In case of a server StaticDomBuilder environment we do nothing never &lt;code&gt;(pure never)&lt;/code&gt;&lt;a href=&quot;#fn7&quot; class=&quot;footnote-ref&quot; id=&quot;fnref7&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;7&lt;/sup&gt;&lt;/a&gt;, in case of a GHCJS DOM environment we do the &lt;code&gt;postLogin&apos;&lt;/code&gt; function. The fmap switchDyn part is to get rid of the dynamic, which is unnecessary because we already return an event. Similar code can be used for all generated endpoints&lt;a href=&quot;#fn8&quot; class=&quot;footnote-ref&quot; id=&quot;fnref8&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;8&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;backend-servant-endpoint&quot;&gt;Backend servant endpoint&lt;/h1&gt;
&lt;p&gt;We need to add an endpoint to servant which will serve the statically rendered HTML. To add it to servant we make an authenticated entry point, which returns &lt;a href=&quot;http://hackage.haskell.org/package/servant-fiat-content-1.0.0/docs/Servant-HTML-Fiat.html&quot;&gt;HTML&lt;/a&gt; as a &lt;code&gt;ByteString&lt;/code&gt;. Because it’s authenticated we can choose what to serve. The authenticated app, if the user has the permission, or the public site, if the user doesn’t have that. It looks like this:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Webservice&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;#cb5-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Auth&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;Cookie&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;JWT&lt;/span&gt;] &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Get&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;HTML&lt;/span&gt;] &lt;span class=&quot;dt&quot;&gt;BS.ByteString&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb5-3&quot;&gt;&lt;a href=&quot;#cb5-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the previous blogpost we’d simply return a ‘401 unauthorized’ status code. Servant auth allows us to decide how to respond. Which we can see in the implementation:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;#cb6-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;renderHtmlEndpoint ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HeadSettings&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AuthResult&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Handler&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;BS.ByteString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;#cb6-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;renderHtmlEndpoint settings authRes &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;#cb6-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;snd&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; liftIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; renderStatic &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;#cb6-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    htmlWidget settings &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; main &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IniState&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; toMaybe authRes&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;main&lt;/code&gt; function is the entry point for the reflex code. We wrap it around in &lt;a href=&quot;https://hackage.haskell.org/package/bulmex-2.0.0/docs/Reflex-Bulmex-Html.html#v:htmlWidget&quot;&gt;&lt;code&gt;htmlWidget&lt;/code&gt;&lt;/a&gt;, which has &lt;a href=&quot;https://hackage.haskell.org/package/bulmex-2.0.0/docs/Reflex-Bulmex-Html.html#t:HeadSettings&quot;&gt;&lt;code&gt;HeadSettings&lt;/code&gt;&lt;/a&gt; to load the JavaScript client as a simple &lt;a href=&quot;https://hackage.haskell.org/package/network-uri-2.6.1.0/docs/Network-URI.html#t:URI&quot;&gt;&lt;code&gt;URI&lt;/code&gt;&lt;/a&gt;. The decision of what to show is completely pushed into the reflex code, the only thing we do at server side is give it the &lt;code&gt;IniState&lt;/code&gt;. Next we’ll discuss how the reflex app decides what to show in this environment.&lt;/p&gt;
&lt;h1 id=&quot;reflex-app&quot;&gt;Reflex App&lt;/h1&gt;
&lt;p&gt;So now we have an &lt;code&gt;IniState&lt;/code&gt; for the app, we can read or write it to the DOM depending on environment. I wrote a function for that. On the app side this is done by &lt;a href=&quot;https://hackage.haskell.org/package/bulmex-2.0.0/docs/Reflex-Bulmex-Html.html#v:writeReadDom&quot;&gt;&lt;code&gt;writeReadDom&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;#cb7-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;writeReadDom ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;#cb7-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( &lt;span class=&quot;dt&quot;&gt;FromJSON&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;#cb7-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    , &lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;#cb7-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    , &lt;span class=&quot;dt&quot;&gt;Dom.DomBuilder&lt;/span&gt; t m&lt;/span&gt;
&lt;span id=&quot;cb7-5&quot;&gt;&lt;a href=&quot;#cb7-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    , &lt;span class=&quot;dt&quot;&gt;Dom.Prerender&lt;/span&gt; js t m&lt;/span&gt;
&lt;span id=&quot;cb7-6&quot;&gt;&lt;a href=&quot;#cb7-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-7&quot;&gt;&lt;a href=&quot;#cb7-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Text.Text&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t a)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first value is the HTML id, the second one is the app state as received by it’s respective endpoint. The result behaves roughly like this:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode html&quot;&gt;&lt;code class=&quot;sourceCode html&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;#cb8-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;&amp;lt;!-- Static dom builder environment (server) --&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;#cb8-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	&lt;span class=&quot;dt&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; id&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;Text.Text&amp;quot;&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; type=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;application/json&amp;quot;&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;#cb8-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;		&lt;span class=&quot;op&quot;&gt;&amp;lt;?&lt;/span&gt;php encode a &lt;span class=&quot;op&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-4&quot;&gt;&lt;a href=&quot;#cb8-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	&lt;span class=&quot;dt&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-5&quot;&gt;&lt;a href=&quot;#cb8-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;&amp;lt;!-- GHCJS environment (browser) --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-6&quot;&gt;&lt;a href=&quot;#cb8-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	JSON.parse(document.getElementById(&amp;quot;Text.Text&amp;quot;));&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Of course the JavaScript will look completely different and the result is put in a dynamic. But the resulting behavior is the same, the server encodes the JSON and the client will decodes it giving us the app state from the server without additional requests. Under the hood &lt;code&gt;prerender&lt;/code&gt; figures out if we need to read or write. All the client needs to do is provide said value, in case of the &lt;a href=&quot;https://github.com/jappeace/awesome-project-name/tree/prerender&quot;&gt;example app&lt;/a&gt; this is just a &lt;code&gt;Maybe User&lt;/code&gt;. The decision of what to display is all integrated within the same reflex code like this:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;#cb9-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;main ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;AWidget&lt;/span&gt; js t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IniState&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m ()&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;#cb9-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;main iniState &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;#cb9-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  iniDyn &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; writeReadDom &lt;span class=&quot;st&quot;&gt;&amp;quot;iniState&amp;quot;&lt;/span&gt; iniState&lt;/span&gt;
&lt;span id=&quot;cb9-4&quot;&gt;&lt;a href=&quot;#cb9-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  rec loginEvt &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; elDynAttr &lt;span class=&quot;st&quot;&gt;&amp;quot;div&amp;quot;&lt;/span&gt; loginAttr &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; loginWidget iniDyn&lt;/span&gt;
&lt;span id=&quot;cb9-5&quot;&gt;&lt;a href=&quot;#cb9-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      loginAttr &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; holdDyn (Map.empty) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; hidden &lt;span class=&quot;op&quot;&gt;&amp;lt;$&lt;/span&gt; loginEvt&lt;/span&gt;
&lt;span id=&quot;cb9-6&quot;&gt;&lt;a href=&quot;#cb9-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  void &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; holdEvent () loginEvt authenticatedWidget&lt;/span&gt;
&lt;span id=&quot;cb9-7&quot;&gt;&lt;a href=&quot;#cb9-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-8&quot;&gt;&lt;a href=&quot;#cb9-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;authenticatedWidget ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;AWidget&lt;/span&gt; js t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m ()&lt;/span&gt;
&lt;span id=&quot;cb9-9&quot;&gt;&lt;a href=&quot;#cb9-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;authenticatedWidget &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We always get an &lt;code&gt;IniState&lt;/code&gt;, but we make sure to first put it in &lt;code&gt;writeReadDom&lt;/code&gt;. This ensures that the &lt;code&gt;IniState&lt;/code&gt; is the actual &lt;code&gt;IniState&lt;/code&gt; from the server and not the one we hardcoded in the executable to make the compiler happy&lt;a href=&quot;#fn9&quot; class=&quot;footnote-ref&quot; id=&quot;fnref9&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;9&lt;/sup&gt;&lt;/a&gt;. This &lt;code&gt;iniDyn&lt;/code&gt; then gets used for the &lt;code&gt;loginWidget&lt;/code&gt; which returns a &lt;code&gt;loginEvt&lt;/code&gt;. If the event fires it has a user, with which we can display the &lt;code&gt;authenticatedWidget&lt;/code&gt;. This is done with help of &lt;code&gt;holdEvent&lt;/code&gt;. Note that if no event is received, no authentication is done. &lt;code&gt;loginAttr&lt;/code&gt; will however become hidden as soon as there is a &lt;code&gt;loginEvt&lt;/code&gt;, hiding the login form. The login widget itself looks like this now:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;#cb10-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;#cb10-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;loginWidget ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;AWidget&lt;/span&gt; js t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t &lt;span class=&quot;dt&quot;&gt;IniState&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;#cb10-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;loginWidget iniDyn &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-4&quot;&gt;&lt;a href=&quot;#cb10-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  pb &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; getPostBuild&lt;/span&gt;
&lt;span id=&quot;cb10-5&quot;&gt;&lt;a href=&quot;#cb10-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  formEvt &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; loginForm&lt;/span&gt;
&lt;span id=&quot;cb10-6&quot;&gt;&lt;a href=&quot;#cb10-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; leftmost [formEvt,&lt;/span&gt;
&lt;span id=&quot;cb10-7&quot;&gt;&lt;a href=&quot;#cb10-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;       noNothing &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; updated &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; userDyn,&lt;/span&gt;
&lt;span id=&quot;cb10-8&quot;&gt;&lt;a href=&quot;#cb10-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;       noNothing &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; current userDyn &lt;span class=&quot;op&quot;&gt;&amp;lt;@&lt;/span&gt; pb]&lt;/span&gt;
&lt;span id=&quot;cb10-9&quot;&gt;&lt;a href=&quot;#cb10-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-10&quot;&gt;&lt;a href=&quot;#cb10-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    userDyn &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; unpackUser &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; iniDyn&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Compared to the &lt;a href=&quot;https://jappieklooster.nl/authentication-in-reflex-servant.html&quot;&gt;previous blogpost&lt;/a&gt; we got rid of &lt;code&gt;autoLogin&lt;/code&gt; and use the &lt;code&gt;IniState&lt;/code&gt; instead. The post build event is used to sample the current value of &lt;code&gt;userDyn&lt;/code&gt;. This ensures a user event fires if there is one available. That mechanism also works for static rendering.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Loading times was one of reflex major weaknesses and this blog post discussed how to mostly remove it. It still takes time before the app becomes interactive, but at least now useful information can be shown to the user instead of a loading screen. I’m really happy with the end result, and I think anyone with a reflex app should seriously consider doing this.&lt;/p&gt;
&lt;h1 id=&quot;references&quot;&gt;References&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jappeace/awesome-project-name/tree/prerender&quot;&gt;Reference project github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://docs.reflex-frp.org/en/latest/reflex_dom_docs.html#prerendering-server-side-rendering&quot;&gt;Official reflex prerender docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hackage.haskell.org/package/reflex-dom-core-0.5/docs/Reflex-Dom-Prerender.html&quot;&gt;Prerender on hackage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hackage.haskell.org/package/reflex-dom-core-0.5/docs/Reflex-Dom-Builder-Static.html#v:renderStatic&quot;&gt;Render static on hackage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/obsidiansystems/obelisk&quot;&gt;Obelisk does already do SSR out of the box&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;Going from 8 seconds in my own app to about 0.5 seconds.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;A prebaked solution is available in &lt;a href=&quot;https://github.com/obsidiansystems/obelisk&quot;&gt;oblisk&lt;/a&gt;, one should consider using that.&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;The server doesn’t need to interpret JavaScript, Haskell can also target native as compile target. But even if it were running JavaScript you can still get speed gains by doing page caching.&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;So it’s not isomorpism categorical terms, but JavaScript terms.&lt;a href=&quot;#fnref4&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn5&quot;&gt;&lt;p&gt;I figured out all this stuff on &lt;a href=&quot;https://www.youtube.com/channel/UCQxmXSQEYyCeBC6urMWRPVw?view_as=subscriber&quot;&gt;stream&lt;/a&gt;&lt;a href=&quot;#fnref5&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn6&quot;&gt;&lt;p&gt;Special thanks to lumie for pointing this out.&lt;a href=&quot;#fnref6&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn7&quot;&gt;&lt;p&gt;I could imagine an alternative design: For example with a micro service setup where you just let the app decide what to call. You’d still need to use a different client on the server side though because it’s native code. But this can be done for with &lt;a href=&quot;http://hackage.haskell.org/package/servant-client&quot;&gt;servant-client&lt;/a&gt;. You define your micro services around the ‘servant’ based REST contracts and let the app pull it in.&lt;a href=&quot;#fnref7&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn8&quot;&gt;&lt;p&gt;It may also be possible to make a more generic function to do this, but I didn’t want to spend the time (I’ve been working on this for days).&lt;a href=&quot;#fnref8&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn9&quot;&gt;&lt;p&gt;I don’t know of a type safe way around this inital state problem. Note that the JavaScript loading by itself is also not type safe, a &lt;code&gt;URI&lt;/code&gt; is used. With that in mind we can kind off consider this the ‘edge’ of the system.&lt;a href=&quot;#fnref9&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Citrix XenCenter 7.6 notes</title>
    <link href="https://jappieklooster.nl/citrix-xencenter-76-notes.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2019-04-18:/citrix-xencenter-76-notes.html</id>
    <published>2019-04-18T00:00:00Z</published>
    <updated>2019-04-18T00:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="pain"/>
    <summary type="html">&lt;p&gt;A client had a Citrix environment running. To debug the deployment of a machine, I copied the Citrix environment locally in VirtualBox. Note that the server doesn’t run any machines inside citrix, but it does get the XenCenter operational. It appears that in nixos you can just setup a local&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;A client had a Citrix environment running. To debug the deployment of a machine, I copied the Citrix environment locally in VirtualBox. Note that the server doesn’t run any machines inside citrix, but it does get the XenCenter operational. It appears that in nixos you can just setup a local &lt;a href=&quot;https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/xen-dom0.nix&quot;&gt;xen server&lt;/a&gt;. The configuration described here will setup a Citrix XenServer that installs and runs, it just can’t run other VM’s. It says it misses HVM.&lt;/p&gt;
&lt;p&gt;This post contains my notes on getting XenCenter operational in VirtualBox. It’s also a guide for people familiar with Linux, but not with Citrix.&lt;/p&gt;
&lt;h1 id=&quot;citrix-xenserver&quot;&gt;Citrix XenServer&lt;/h1&gt;
&lt;p&gt;It’s actually CentOS with XenServer installed on it. The VM shell will drop you into a ncurses menu which has an option to go to a bash shell.&lt;/p&gt;
&lt;p&gt;The branding says it’s a ‘smaller’ operating system, looks pretty complete to me though. I think they mean that they have kernel modules that may allow the guest VM’s to use hardware directly. To do this you have to modify the host as well as the guest OS. They both have to understand the virtualization situation.&lt;/p&gt;
&lt;p&gt;If you want to do this properly you should seriously consider &lt;a href=&quot;https://www.youtube.com/watch?v=xXWaECk9XqM&quot;&gt;containers&lt;/a&gt;. Even though virtual machines are &lt;a href=&quot;https://www.infoworld.com/article/3071679/linux-containers-vs-vms-a-security-comparison.html&quot;&gt;more secure&lt;/a&gt; and virtual machines are more portable&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;, the trade off however is that virtual machines are really inneficient. Giving them direct access to hardware won’t change the nature of OS kernels. To hog all resources, which they have to do to manage them. A container setup will simply have a single kernel, yet many operating systems (user spaces).&lt;/p&gt;
&lt;h2 id=&quot;get-xenserver&quot;&gt;Get XenServer&lt;/h2&gt;
&lt;p&gt;Go to &lt;a href=&quot;https://www.citrix.com&quot;&gt;citrix.com&lt;/a&gt;, you must get it from there. Don’t bother googling this. Google doesn’t find the download. You &lt;em&gt;have&lt;/em&gt; to make an account to download it.&lt;/p&gt;
&lt;p&gt;Then go for the &lt;code&gt;citrix hypervisor&lt;/code&gt; in the downloads area. By the way: &lt;code&gt;XenServer = citrix hypervisor&lt;/code&gt; I think the only thing they did to the XenServer is add branding.&lt;/p&gt;
&lt;h2 id=&quot;get-client&quot;&gt;Get client&lt;/h2&gt;
&lt;p&gt;The XenServer also contains the client. No need to download any of the other stuff. XenServer is one of the many products hosted by citrix.&lt;/p&gt;
&lt;h1 id=&quot;you-can-run-xenserver-in-virtual-box&quot;&gt;You can run XenServer in virtual box&lt;/h1&gt;
&lt;p&gt;You need enough RAM though, just create a &lt;a href=&quot;https://linuxize.com/post/create-a-linux-swap-file/&quot;&gt;swap file&lt;/a&gt; if you run into trouble.&lt;/p&gt;
&lt;p&gt;Make sure to &lt;a href=&quot;https://superuser.com/questions/227505/what-is-the-difference-between-nat-bridged-host-only-networking&quot;&gt;bridge&lt;/a&gt; it on a device like WIFI. This allows one VM to access another VM. Also put promiscuous mode on allow all. I think this is why I couldn’t transfer the VHD.&lt;/p&gt;
&lt;p&gt;Install it, go into the root shell and type &lt;code&gt;ip addr&lt;/code&gt; to get the ip. We need this for the client.&lt;/p&gt;
&lt;h2 id=&quot;creating-an-extra-storage-repository&quot;&gt;Creating an extra storage repository:&lt;/h2&gt;
&lt;p&gt;For some reason the XenServer created a very small 8G repository, I just added another disk with VirtualBox and then ran this on the XenServer vm shell:&lt;/p&gt;
&lt;pre class=&quot;shell&quot;&gt;&lt;code&gt;xe sr-create name-label=&amp;lt;Storage ID&amp;gt; shared=false device-config:device=&amp;lt;Path of the Storage device&amp;gt; type=lvm content-type=user&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Actually I attempted to partition it, but I think the command already does that. If not see my other post where &lt;a href=&quot;%7Bfilename%7D/nixos-encrypted-btrfs.md&quot;&gt;gdisk&lt;/a&gt; is explained.&lt;/p&gt;
&lt;h1 id=&quot;use-the-windows-client&quot;&gt;Use the windows client&lt;/h1&gt;
&lt;p&gt;I couldn’t get the citrix Linux client to work on nixos. I attempted &lt;a href=&quot;https://libvirt.org/&quot;&gt;libvirt&lt;/a&gt; because it supports remote but it seemed fairly complicated. I ran the XenCenter client in the &lt;a href=&quot;https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/&quot;&gt;edge iso&lt;/a&gt; provided by MS. This VM was bridged too.&lt;/p&gt;
&lt;p&gt;Once inside the VM, click on a VMDK to import it into XenCenter. I could find no way of doing this in the XenCenter program itself. Also make sure to have a server selected before importing it, otherwise you’ll get a null reference error on the storage screen. It apparently uses the selected one instead of the location from previous screen.&lt;/p&gt;
&lt;h2 id=&quot;log-for-notices&quot;&gt;Log for notices&lt;/h2&gt;
&lt;p&gt;If you ever get a “generic error”, check the log:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    C:\Users\IEUser\AppData\Roaming\Citrix\XenCenter\logs&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is a ton of information in that. Pasting the relevant part into google will get you more progress than “generic error”.&lt;/p&gt;
&lt;h1 id=&quot;virtualbox-vmdks&quot;&gt;VirtualBox VMDKs&lt;/h1&gt;
&lt;p&gt;Citrix XenServer does not appear to accept VirtualBox VMDKs. I got VHD to work locally, but for some reason it didn’t work at the client. If you want a NixOS VHD checkout &lt;a href=&quot;%7Bfilename%7D/nixos-notes.md&quot;&gt;this post&lt;/a&gt;&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;If you mix OS’es for some reason you’re right in using virtual machines&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Nixos notes</title>
    <link href="https://jappieklooster.nl/nixos-notes.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2019-04-18:/nixos-notes.html</id>
    <published>2019-04-18T00:00:00Z</published>
    <updated>2019-04-18T00:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;This is a post of things I wanted to do in nixos but isn’t described anywhere. I had to read source code to figure these things out. By explaining here what is going on I make things easier for other people.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2019/nixos_notes.svg&quot; alt=&quot;Nixos notes&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Nixos notes&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1 id=&quot;nix-custom-image&quot;&gt;Nix custom image&lt;/h1&gt;
&lt;p&gt;It’s possible to bypass&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;This is a post of things I wanted to do in nixos but isn’t described anywhere. I had to read source code to figure these things out. By explaining here what is going on I make things easier for other people.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2019/nixos_notes.svg&quot; alt=&quot;Nixos notes&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Nixos notes&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1 id=&quot;nix-custom-image&quot;&gt;Nix custom image&lt;/h1&gt;
&lt;p&gt;It’s possible to bypass virtual box and make a bunch of different image formats directly, I used two files &lt;code&gt;image.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode nix&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;:&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;pkgs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;./pin.nix&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;#cb1-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;#cb1-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;#cb1-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;#cb1-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;system&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;build&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; &amp;lt;&lt;span class=&quot;ss&quot;&gt;nixpkgs/nixos/lib/make-disk-image.nix&lt;/span&gt;&amp;gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;#cb1-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;nixos-vmdk-&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;${&lt;/span&gt;config&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;system&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;nixos&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;label&lt;span class=&quot;sc&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;${&lt;/span&gt;pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;stdenv&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;hostPlatform&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;system&lt;span class=&quot;sc&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-10&quot;&gt;&lt;a href=&quot;#cb1-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;vpc&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-11&quot;&gt;&lt;a href=&quot;#cb1-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;kw&quot;&gt;inherit&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;pkgs&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-12&quot;&gt;&lt;a href=&quot;#cb1-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;lib&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;lib&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-13&quot;&gt;&lt;a href=&quot;#cb1-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;partitionTableType&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;legacy&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-14&quot;&gt;&lt;a href=&quot;#cb1-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;diskSize&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;11&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-15&quot;&gt;&lt;a href=&quot;#cb1-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-16&quot;&gt;&lt;a href=&quot;#cb1-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  .... &lt;span class=&quot;co&quot;&gt;# remaining config, same as configuration.nix&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-17&quot;&gt;&lt;a href=&quot;#cb1-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and the &lt;code&gt;disk.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode nix&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;nixos&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;?&lt;/span&gt; &amp;lt;&lt;span class=&quot;ss&quot;&gt;nixpkgs/nixos&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;system&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;builtins&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;currentSystem&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;#cb2-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;:&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;#cb2-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;#cb2-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;#cb2-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;machine-configuration&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;./image.nix&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;#cb2-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;machine&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; nixos &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-8&quot;&gt;&lt;a href=&quot;#cb2-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;inherit&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-9&quot;&gt;&lt;a href=&quot;#cb2-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;configuration&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; machine&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;configuration&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-10&quot;&gt;&lt;a href=&quot;#cb2-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-11&quot;&gt;&lt;a href=&quot;#cb2-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb2-12&quot;&gt;&lt;a href=&quot;#cb2-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;machine&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;config&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;system&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;build&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;image&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you run &lt;code&gt;nix-build disk.nix&lt;/code&gt; you’ll get a VHD with the configuration from &lt;code&gt;image.nix&lt;/code&gt; which is just a nixos standard &lt;code&gt;configuraiton.nix&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&quot;nixos-rebuild-remote&quot;&gt;Nixos-rebuild remote&lt;/h1&gt;
&lt;p&gt;We can use nixos-rebuild to do in place updates of a running system remotely. If your deployment is a single VM this is significantly easier than using nixops. I ended up with this make file:&lt;/p&gt;
&lt;pre class=&quot;shell&quot;&gt;&lt;code&gt;IP=&amp;quot;192.168.0.39&amp;quot;
deploy: 
	NIXOS_CONFIG=$(shell pwd)&amp;quot;/image.nix&amp;quot; nixos-rebuild switch --target-host root@$(IP)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You may also want to set &lt;code&gt;--build-host&lt;/code&gt;, because by default it will build on &lt;code&gt;target-host&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&quot;install-nix-on-running-nix&quot;&gt;Install nix on running nix&lt;/h1&gt;
&lt;p&gt;For some reason my boot disk gets corrupted after switching a couple of times. A solution is just to never reboot, however you can also just fix this while running the system. Switching doesn’t do this apparently. I know this because it didn’t boot. This doesn’t matter because you can install your currently running system!&lt;/p&gt;
&lt;p&gt;Mount root as &lt;code&gt;/mnt&lt;/code&gt;. Format your boot partition and mount it on &lt;code&gt;/mnt/boot&lt;/code&gt;. Then run &lt;code&gt;nixos-install&lt;/code&gt;. For example:&lt;/p&gt;
&lt;pre class=&quot;shell&quot;&gt;&lt;code&gt;mount # list everything mounted
mount /dev/nvme0n1p2 /mnt
umount /boot
mkfs.vfat -n boot /dev/nvme0n1p1
mount /dev/nvme0n1p1 /boot
mount /dev/nvme0n1p1 /mnt/boot&lt;/code&gt;&lt;/pre&gt;</content>
  </entry>
  <entry>
    <title>Authentication in Reflex &amp; Servant</title>
    <link href="https://jappieklooster.nl/authentication-in-reflex-servant.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2019-02-28:/authentication-in-reflex-servant.html</id>
    <published>2019-02-28T15:00:00Z</published>
    <updated>2019-02-28T15:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;In the previous &lt;a href=&quot;%7Bfilename%7D/fullstack-haskell-reflex-servant.md&quot;&gt;blog post&lt;/a&gt; we saw interaction with servant in reflex. Although that covers the basics, there are several more hurdles to overcome to get comfortable with Reflex. I think most of these are encountered by building a simple login system. So let’s build something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;													
                   	   +------------------+
   +-----------+       |&lt;/code&gt;&lt;/pre&gt;</summary>
    <content type="html">&lt;p&gt;In the previous &lt;a href=&quot;%7Bfilename%7D/fullstack-haskell-reflex-servant.md&quot;&gt;blog post&lt;/a&gt; we saw interaction with servant in reflex. Although that covers the basics, there are several more hurdles to overcome to get comfortable with Reflex. I think most of these are encountered by building a simple login system. So let’s build something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;													
                   	   +------------------+
   +-----------+       |    .      -      |
   | +--------+|       | .    -  .. .     |
   | +--------+|       | . .-- - + m..-.  |
   | +--------+|    \  |   m# + .-..% -   |
   | +--------+|     \ |   + .+ #.+...+   |
   | login ----+------X|    .. -.- *      |
   +-----------+     / |    ..  ..-#+ +   |
                    /  |      .  - -. .   |
                   	   |         . .      |
					   |          -       |
					   |                  |
		     		   +------------------+
					        Awesome app	
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ve experienced that this is hard for the first time. With this blog post I hope that setting up authentication becomes easier, considering the following pain points:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;‘Switching screens’ after login, requires &lt;a href=&quot;https://wiki.haskell.org/MonadFix&quot;&gt;recursive do&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://hackage.haskell.org/package/servant-auth-server-0.4.3.0/docs/Servant-Auth-Server.html&quot;&gt;Dealing with cookies&lt;/a&gt; yourself is pretty hard, many pesky (security) details.&lt;/li&gt;
&lt;li&gt;Rendering widgets inside FRP constructs requires &lt;a href=&quot;https://hackage.haskell.org/package/reflex-dom-core-0.4/docs/Reflex-Dom-Widget-Basic.html#v:widgetHold&quot;&gt;widgetHold&lt;/a&gt; or ‘dyn’.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I’m of course a world expert on login systems, so in production do everything exactly as I do. Trust me, I’m from the internet. But seriously If you see something dubious, do contact me. I’ll happily rectify mistakes, and put you on the &lt;a href=&quot;/pages/page-of-honour.html&quot;&gt;page of honour&lt;/a&gt; (if you want).&lt;/p&gt;
&lt;p&gt;I left some code out of this blog post for succinctness. But the full source is available on &lt;a href=&quot;https://github.com/jappeace/awesome-project-name/tree/auth&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;api-endpoints&quot;&gt;API Endpoints&lt;/h1&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ServiceAPI&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PublicAPI&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Auth&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;Cookie&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;JWT&lt;/span&gt;] &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AuthAPI&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;First we need to split our API into two types. The &lt;code&gt;PublicAPI&lt;/code&gt; and the &lt;code&gt;AuthAPI&lt;/code&gt;. Once the user is logged in he gets access to the &lt;code&gt;AuthAPI&lt;/code&gt;. We’ll secure this with a JWT cookie. If the user does not have a proper cookie, he’ll get a &lt;a href=&quot;https://tools.ietf.org/html/rfc7235#section-3.1&quot;&gt;401 unauthorized&lt;/a&gt; status code.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PublicAPI&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;api&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;login&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ReqBody&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;#cb3-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;								&lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Post&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] (&lt;span class=&quot;dt&quot;&gt;AuthCookies&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NoContent&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is our entire public api, we only expose the login endpoint. The result contains no content, but cookies. Servant assumes all status codes are possible in every request. Therefore we don’t have to mention the 401 status code.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;#cb4-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AuthAPI&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;#cb4-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           &lt;span class=&quot;st&quot;&gt;&amp;quot;api&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;me&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Get&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;#cb4-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;api&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;users&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Get&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] [&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb4-4&quot;&gt;&lt;a href=&quot;#cb4-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;api&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ReqBody&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-5&quot;&gt;&lt;a href=&quot;#cb4-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;						  &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Post&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] [&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;AuthAPI&lt;/code&gt; is similar to the &lt;code&gt;ServiceAPI&lt;/code&gt; from the &lt;a href=&quot;%7Bfilename%7D/fullstack-haskell-reflex-servant.md&quot;&gt;previous blog post&lt;/a&gt;, which only contained the &lt;code&gt;users&lt;/code&gt; and &lt;code&gt;message&lt;/code&gt; endpoints. Now we’ve extended it with a &lt;code&gt;getme&lt;/code&gt; endpoint. The &lt;code&gt;getme&lt;/code&gt; endpoint is a hack to do auto login with cookies. It allows us to do a request on initial page load to see if we have the cookies or not. Technically we shouldn’t have to do this trough a request, but it works for version &lt;code&gt;0.1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next we’ll implement these types into handlers:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;login ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ApiSettings&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Handler&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;AuthCookies&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NoContent&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;#cb5-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;login settings user &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;elem&lt;/span&gt; user users &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-3&quot;&gt;&lt;a href=&quot;#cb5-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	withCookies &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; liftIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-4&quot;&gt;&lt;a href=&quot;#cb5-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;		acceptLogin cookies (jwtSettings settings) user&lt;/span&gt;
&lt;span id=&quot;cb5-5&quot;&gt;&lt;a href=&quot;#cb5-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	&lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;maybe&lt;/span&gt; (clearSession cookies &lt;span class=&quot;dt&quot;&gt;NoContent&lt;/span&gt;) (\x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x &lt;span class=&quot;dt&quot;&gt;NoContent&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb5-6&quot;&gt;&lt;a href=&quot;#cb5-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;		withCookies&lt;/span&gt;
&lt;span id=&quot;cb5-7&quot;&gt;&lt;a href=&quot;#cb5-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; throwAll err401 &lt;span class=&quot;co&quot;&gt;-- unauthorized&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-8&quot;&gt;&lt;a href=&quot;#cb5-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-9&quot;&gt;&lt;a href=&quot;#cb5-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    cookies &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; cookieSettings settings&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We added a new login handler, which checks if the user exists within the users list. If the user is in the list, we use &lt;code&gt;acceptLogin&lt;/code&gt; to create a JWT from the user. &lt;code&gt;[A]cceptLogin&lt;/code&gt; returns maybe a function which applies the JWT cookie. In the success branch of maybe we apply this function to &lt;code&gt;NoContent&lt;/code&gt; to get an &lt;code&gt;AuthCookies NoContent&lt;/code&gt;. The &lt;code&gt;Nothing&lt;/code&gt; branch also produces &lt;code&gt;AuthCookies NoConent&lt;/code&gt;, but it sets the cookie values with &lt;code&gt;clearSession&lt;/code&gt; resulting in nothing instead of a JWT.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ApiSettings&lt;/code&gt; is just a data type with various configurations:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;#cb6-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ApiSettings&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ApiSettings&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;#cb6-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; cookieSettings ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;CookieSettings&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;#cb6-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; jwtSettings    ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JWTSettings&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;#cb6-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; connection     ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;#cb6-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can’t use connection like this in production, it needs to be a &lt;a href=&quot;http://hackage.haskell.org/package/resource-pool-0.2.3.2/docs/Data-Pool.html&quot;&gt;pool&lt;/a&gt;, because servant is &lt;a href=&quot;https://www.reddit.com/r/haskell/comments/4tq2q0/does_servant_run_on_multicore_cpu/&quot;&gt;fully concurrent&lt;/a&gt;. You’ll end up with data races if you use a plain connection.&lt;/p&gt;
&lt;p&gt;For the &lt;code&gt;cookieSettings&lt;/code&gt; I modified the defaults quite a bit:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;#cb7-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;cookieConf &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;#cb7-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  defaultCookieSettings&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;#cb7-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    { cookieIsSecure &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NotSecure&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;#cb7-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    , cookieMaxAge &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; secondsToDiffTime &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;24&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;365&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-5&quot;&gt;&lt;a href=&quot;#cb7-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    , cookieXsrfSetting &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-6&quot;&gt;&lt;a href=&quot;#cb7-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        def { xsrfCookieName &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Text.encodeUtf8 cookieName&lt;/span&gt;
&lt;span id=&quot;cb7-7&quot;&gt;&lt;a href=&quot;#cb7-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            , xsrfHeaderName &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Text.encodeUtf8 headerName&lt;/span&gt;
&lt;span id=&quot;cb7-8&quot;&gt;&lt;a href=&quot;#cb7-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            }&lt;/span&gt;
&lt;span id=&quot;cb7-9&quot;&gt;&lt;a href=&quot;#cb7-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-10&quot;&gt;&lt;a href=&quot;#cb7-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Cookies are set to &lt;code&gt;NotSecure&lt;/code&gt; to allow it to work on HTTP. This is required for local testing, and avoids confusion about why your cookies, and your entire login system, don’t work locally. You should simply disable HTTP in production anyway. There is no good reason for using plain HTTP on a live website, ever since &lt;a href=&quot;https://letsencrypt.org/&quot;&gt;let’s encrypt&lt;/a&gt; became a thing.&lt;/p&gt;
&lt;p&gt;The max age is simply an auto sign out after a period, a year in this case. This is a bit more secure because we don’t trust someone’s login forever.&lt;/p&gt;
&lt;p&gt;XSRF settings are set to use the names from the Common XSRF module. This ensures the requests from the frontend use the same names as servant-auth expects.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;#cb8-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;authenticatedServer ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ApiSettings&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AuthResult&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AuthAPI&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;#cb8-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;authenticatedServer settings (&lt;span class=&quot;dt&quot;&gt;Authenticated&lt;/span&gt; user) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;#cb8-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; user &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; users &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; messages (connection settings))&lt;/span&gt;
&lt;span id=&quot;cb8-4&quot;&gt;&lt;a href=&quot;#cb8-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;authenticatedServer _ _ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; throwAll err401 &lt;span class=&quot;co&quot;&gt;-- unauthorized&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;authenticatedServer&lt;/code&gt; handles the endpoints for the authenticated API. The only new one is &lt;code&gt;getMe&lt;/code&gt;, which just returns the authenticated user. All authenticated endpoints now have access to the user who was authenticated. This user is decoded from the JWT by servant-auth.&lt;/p&gt;
&lt;p&gt;We get an &lt;code&gt;AuthResult&lt;/code&gt; from servant-auth-server to work with. If the user is authenticated, we give access to the API, if not we return a 401 status code. This is done manually, which means the 401 response is not mandatory.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;#cb9-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;server ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ApiSettings&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Webservice&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;#cb9-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;server settings staticFolder &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;#cb9-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	(login settings &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; authenticatedServer settings)&lt;/span&gt;
&lt;span id=&quot;cb9-4&quot;&gt;&lt;a href=&quot;#cb9-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	&lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; serveDirectoryFileServer staticFolder&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The server function now has to split our API on authenticated and public parts. It’s similar to the previous blog post. We still serve the static folder for testing.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;#cb10-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;app ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ApiSettings&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Application&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;#cb10-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;app settings staticFolder &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;#cb10-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  serveWithContext webservice context &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; server settings staticFolder&lt;/span&gt;
&lt;span id=&quot;cb10-4&quot;&gt;&lt;a href=&quot;#cb10-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-5&quot;&gt;&lt;a href=&quot;#cb10-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    context &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; cookieSettings settings &lt;span class=&quot;op&quot;&gt;:.&lt;/span&gt; jwtSettings settings &lt;span class=&quot;op&quot;&gt;:.&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EmptyContext&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We now serve with context, this is the servant-auth entry point for decoding of the JWT from the Cookie.&lt;/p&gt;
&lt;p&gt;This is probably not the way you want to do login on the sever side for the following reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We don’t handle passwords, period. (Authentication by trust is a thing?)&lt;/li&gt;
&lt;li&gt;One shouldn’t use JWT’s for &lt;a href=&quot;http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/&quot;&gt;sessions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Solving these issues is out of the scope of this article[^scope]. [^scope]: My articles tend to snowball anyway, for example invented how to do XSRF specifically for this article. I Don’t want to cargo cult a bunch of XSRF vulnerable websites.&lt;/p&gt;
&lt;p&gt;The client API is much simpler:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb11&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb11-1&quot;&gt;&lt;a href=&quot;#cb11-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;postLogin ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m&lt;/span&gt;
&lt;span id=&quot;cb11-2&quot;&gt;&lt;a href=&quot;#cb11-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text.Text&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb11-3&quot;&gt;&lt;a href=&quot;#cb11-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t ()&lt;/span&gt;
&lt;span id=&quot;cb11-4&quot;&gt;&lt;a href=&quot;#cb11-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;ReqResult&lt;/span&gt; () (&lt;span class=&quot;dt&quot;&gt;AuthCookies&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NoContent&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb11-5&quot;&gt;&lt;a href=&quot;#cb11-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;getUsers ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m&lt;/span&gt;
&lt;span id=&quot;cb11-6&quot;&gt;&lt;a href=&quot;#cb11-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t ()&lt;/span&gt;
&lt;span id=&quot;cb11-7&quot;&gt;&lt;a href=&quot;#cb11-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;ReqResult&lt;/span&gt; () [&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;]))&lt;/span&gt;
&lt;span id=&quot;cb11-8&quot;&gt;&lt;a href=&quot;#cb11-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;getMe ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m&lt;/span&gt;
&lt;span id=&quot;cb11-9&quot;&gt;&lt;a href=&quot;#cb11-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t ()&lt;/span&gt;
&lt;span id=&quot;cb11-10&quot;&gt;&lt;a href=&quot;#cb11-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;ReqResult&lt;/span&gt; () &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb11-11&quot;&gt;&lt;a href=&quot;#cb11-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;postMessage ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m&lt;/span&gt;
&lt;span id=&quot;cb11-12&quot;&gt;&lt;a href=&quot;#cb11-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text.Text&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb11-13&quot;&gt;&lt;a href=&quot;#cb11-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t ()&lt;/span&gt;
&lt;span id=&quot;cb11-14&quot;&gt;&lt;a href=&quot;#cb11-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;ReqResult&lt;/span&gt; () [&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;]))&lt;/span&gt;
&lt;span id=&quot;cb11-15&quot;&gt;&lt;a href=&quot;#cb11-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(postLogin &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; (getMe &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; getUsers &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; postMessage)) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; apiClients&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The clients are still generated, the only thing I’ve done is spell out the type signatures.&lt;/p&gt;
&lt;h1 id=&quot;reflex&quot;&gt;Reflex&lt;/h1&gt;
&lt;p&gt;Time for some reflex. The reflex changes are rather small but dense:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;#cb12-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;loginWidget ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb12-2&quot;&gt;&lt;a href=&quot;#cb12-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;loginWidget &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-3&quot;&gt;&lt;a href=&quot;#cb12-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  autoLoginEvt &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; autoLogin&lt;/span&gt;
&lt;span id=&quot;cb12-4&quot;&gt;&lt;a href=&quot;#cb12-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  formEvt &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; loginForm&lt;/span&gt;
&lt;span id=&quot;cb12-5&quot;&gt;&lt;a href=&quot;#cb12-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; leftmost [formEvt, autoLoginEvt]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This function performs either an auto login, or shows a login form. leftmost is a function that combines events, by using the value of whichever fires. If they fire both, the element that occurs first in the list is used. Hence the name leftmost.&lt;/p&gt;
&lt;p&gt;Now let’s dive into it’s sub components, first &lt;code&gt;autologin&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb13&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb13-1&quot;&gt;&lt;a href=&quot;#cb13-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;autoLogin ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb13-2&quot;&gt;&lt;a href=&quot;#cb13-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;autoLogin &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-3&quot;&gt;&lt;a href=&quot;#cb13-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  pb &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; getPostBuild&lt;/span&gt;
&lt;span id=&quot;cb13-4&quot;&gt;&lt;a href=&quot;#cb13-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  withSuccess &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; getMe pb&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We get the &lt;a href=&quot;https://hackage.haskell.org/package/reflex-0.5/docs/Reflex-PostBuild-Class.html&quot;&gt;post build event&lt;/a&gt;, an event that fires after the widget is placed in the DOM. We use that to greedily to make the &lt;code&gt;getMe&lt;/code&gt; request. If successful that is used as the resulting event. However the loginWidget makes a login form regardless of success:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb14-1&quot;&gt;&lt;a href=&quot;#cb14-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;userInput ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb14-2&quot;&gt;&lt;a href=&quot;#cb14-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;userInput &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-3&quot;&gt;&lt;a href=&quot;#cb14-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-4&quot;&gt;&lt;a href=&quot;#cb14-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;loginForm ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb14-5&quot;&gt;&lt;a href=&quot;#cb14-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;loginForm &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-6&quot;&gt;&lt;a href=&quot;#cb14-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  user &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; userInput&lt;/span&gt;
&lt;span id=&quot;cb14-7&quot;&gt;&lt;a href=&quot;#cb14-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  buttonEvt &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; button &lt;span class=&quot;st&quot;&gt;&amp;quot;login&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-8&quot;&gt;&lt;a href=&quot;#cb14-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  postResult &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; postLogin (&lt;span class=&quot;dt&quot;&gt;Right&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; user) buttonEvt&lt;/span&gt;
&lt;span id=&quot;cb14-9&quot;&gt;&lt;a href=&quot;#cb14-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  void &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; flash postResult &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; text &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; Text.pack &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; reqFailure&lt;/span&gt;
&lt;span id=&quot;cb14-10&quot;&gt;&lt;a href=&quot;#cb14-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; current user &lt;span class=&quot;op&quot;&gt;&amp;lt;@&lt;/span&gt; withSuccess postResult&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;userInput&lt;/code&gt; has remained the same as in the &lt;a href=&quot;%7Bfilename%7D/fullstack-haskell-reflex-servant.md&quot;&gt;previous blog post&lt;/a&gt;. After the &lt;code&gt;userInput&lt;/code&gt; form we create a button, which gives us a resulting &lt;code&gt;buttonEvt&lt;/code&gt; event. This event only fires if the button is pressed. We use the &lt;code&gt;buttonEvt&lt;/code&gt; to call &lt;code&gt;postLogin&lt;/code&gt;. As input we use the dynamic &lt;code&gt;user&lt;/code&gt; from the &lt;code&gt;userInput&lt;/code&gt; form. This gives us a &lt;code&gt;postResultEvt&lt;/code&gt;, an event that only fires on request completion. Remember &lt;code&gt;postLogin&lt;/code&gt; is a function generated from our API type signature:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb15&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb15-1&quot;&gt;&lt;a href=&quot;#cb15-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;postLogin ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m&lt;/span&gt;
&lt;span id=&quot;cb15-2&quot;&gt;&lt;a href=&quot;#cb15-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text.Text&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb15-3&quot;&gt;&lt;a href=&quot;#cb15-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t ()&lt;/span&gt;
&lt;span id=&quot;cb15-4&quot;&gt;&lt;a href=&quot;#cb15-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;ReqResult&lt;/span&gt; () (&lt;span class=&quot;dt&quot;&gt;AuthCookies&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NoContent&lt;/span&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;ReqResult&lt;/code&gt; is a container for dealing with HTTP status codes, connection errors and decoding issues &lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;. In case of failure the &lt;code&gt;postResultEvt&lt;/code&gt; is ‘flashed’, or shown briefly for a couple of seconds. In case of success we tag the &lt;code&gt;postResultEvt&lt;/code&gt; with the &lt;code&gt;user&lt;/code&gt; and use that as resulting event.&lt;/p&gt;
&lt;p&gt;Note that &lt;code&gt;&amp;lt;@&lt;/code&gt;, is the same as &lt;code&gt;&amp;lt;$&lt;/code&gt;, except it works on behaviors: The event gets the value of whatever the behavior is at the time of the event. A behavior is something that always has a value, but which can change at any moment. Whereas an event is something that happens at a point in time with some value. A mouse position is an example of behavior, whereas a mouse click is an event&lt;a href=&quot;#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Next we move onto the function that ties everything together:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb16&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb16-1&quot;&gt;&lt;a href=&quot;#cb16-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;reflex ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m ()&lt;/span&gt;
&lt;span id=&quot;cb16-2&quot;&gt;&lt;a href=&quot;#cb16-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;reflex &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-3&quot;&gt;&lt;a href=&quot;#cb16-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  rec loginEvt &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; elDynAttr &lt;span class=&quot;st&quot;&gt;&amp;quot;div&amp;quot;&lt;/span&gt; loginAttr loginWidget&lt;/span&gt;
&lt;span id=&quot;cb16-4&quot;&gt;&lt;a href=&quot;#cb16-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      loginAttr &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; holdDyn (Map.empty) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; hidden &lt;span class=&quot;op&quot;&gt;&amp;lt;$&lt;/span&gt; loginEvt&lt;/span&gt;
&lt;span id=&quot;cb16-5&quot;&gt;&lt;a href=&quot;#cb16-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  void &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; holdEvent () loginEvt authenticatedWidget&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once the login event happens this function will hide the &lt;code&gt;loginWidget&lt;/code&gt; and put the &lt;code&gt;authenticatedWidget&lt;/code&gt; on the DOM. &lt;code&gt;loginAttr&lt;/code&gt; is used before it’s assigned however. This is impossible in a normal do block, but it is possible within a &lt;code&gt;rec&lt;/code&gt; block. The &lt;code&gt;rec&lt;/code&gt; keyword is from &lt;a href=&quot;https://wiki.haskell.org/MonadFix&quot;&gt;recursive do&lt;/a&gt;. It allows referencing of variables ‘higher’ in a do block. In our case we need to have &lt;code&gt;loginAttr&lt;/code&gt; within the &lt;code&gt;elDynAttr&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;I don’t want to go into how &lt;code&gt;rec&lt;/code&gt; works&lt;a href=&quot;#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;, but I do want to make clear why it’s needed. There is a reference cycle&lt;a href=&quot;#fn4&quot; class=&quot;footnote-ref&quot; id=&quot;fnref4&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt;. Look closely at &lt;code&gt;loginAttr&lt;/code&gt;. It depends on &lt;code&gt;loginEvt&lt;/code&gt;. Now look at how the &lt;code&gt;loginEvt&lt;/code&gt; is made. It comes from a div that requires &lt;code&gt;loginAttr&lt;/code&gt;. A cycle. I don’t know of any other way to solve this than using recursive do.&lt;/p&gt;
&lt;p&gt;So the login widget resides in a &lt;code&gt;div&lt;/code&gt; with dynamic attributes. These attributes are set on the next line, which starts out as an empty Map, no attributes. Once the login event happens, it becomes the &lt;code&gt;hidden&lt;/code&gt;, which sets the style to &lt;code&gt;display:none&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;holdEvent&lt;/code&gt; is used to extract the user as a value from the event and render &lt;code&gt;authenticatedWidget&lt;/code&gt; as a new part of the DOM. The &lt;code&gt;holdEvent&lt;/code&gt; functions is a convenience function for &lt;a href=&quot;https://hackage.haskell.org/package/reflex-dom-core-0.4/docs/Reflex-Dom-Widget-Basic.html#v:widgetHold&quot;&gt;widgetHold&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb17&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb17-1&quot;&gt;&lt;a href=&quot;#cb17-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;widgetHold ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;DomBuilder&lt;/span&gt; t m, &lt;span class=&quot;dt&quot;&gt;MonadHold&lt;/span&gt; t m)&lt;/span&gt;
&lt;span id=&quot;cb17-2&quot;&gt;&lt;a href=&quot;#cb17-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m a&lt;/span&gt;
&lt;span id=&quot;cb17-3&quot;&gt;&lt;a href=&quot;#cb17-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t (m a)&lt;/span&gt;
&lt;span id=&quot;cb17-4&quot;&gt;&lt;a href=&quot;#cb17-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t a) &lt;/span&gt;
&lt;span id=&quot;cb17-5&quot;&gt;&lt;a href=&quot;#cb17-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-6&quot;&gt;&lt;a href=&quot;#cb17-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;holdEvent ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Dom.DomBuilder&lt;/span&gt; t m, &lt;span class=&quot;dt&quot;&gt;MonadHold&lt;/span&gt; t m)&lt;/span&gt;
&lt;span id=&quot;cb17-7&quot;&gt;&lt;a href=&quot;#cb17-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; b&lt;/span&gt;
&lt;span id=&quot;cb17-8&quot;&gt;&lt;a href=&quot;#cb17-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t a&lt;/span&gt;
&lt;span id=&quot;cb17-9&quot;&gt;&lt;a href=&quot;#cb17-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m b)&lt;/span&gt;
&lt;span id=&quot;cb17-10&quot;&gt;&lt;a href=&quot;#cb17-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t b)&lt;/span&gt;
&lt;span id=&quot;cb17-11&quot;&gt;&lt;a href=&quot;#cb17-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;holdEvent val evt fun &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-12&quot;&gt;&lt;a href=&quot;#cb17-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  Dom.widgetHold (&lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; val) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; fun &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; evt&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;widgetHold&lt;/code&gt; will show the first given widget, until the event happens which has a widget as value. Then the widget within that event is put onto the DOM instead of the original. It’s a bit like &lt;a href=&quot;http://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Traversable.html#v:sequence&quot;&gt;sequence&lt;/a&gt;&lt;a href=&quot;#fn5&quot; class=&quot;footnote-ref&quot; id=&quot;fnref5&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt;. In any case it returns the widget value as a dynamic.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;holdEvent&lt;/code&gt; however assumes we initially don’t want to render anything on the DOM. Then it asks you to provide an event with any value and finally a function that consumes the value to produce the widget. It will execute the function and display the resulting widget on the DOM instead of nothing.&lt;/p&gt;
&lt;p&gt;The first argument of &lt;code&gt;holdEvent&lt;/code&gt; is the default value. The second argument is the event which we want to hold. The final argument is the function we want to execute producing a widget. The function keeps returning the default value until the event fires for the first time, then it will keep on displaying the fired event.&lt;/p&gt;
&lt;p&gt;Note that &lt;code&gt;widgetHold&lt;/code&gt; is slow &lt;a href=&quot;#fn6&quot; class=&quot;footnote-ref&quot; id=&quot;fnref6&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;6&lt;/sup&gt;&lt;/a&gt; because it modifies the DOM &lt;a href=&quot;#fn7&quot; class=&quot;footnote-ref&quot; id=&quot;fnref7&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;7&lt;/sup&gt;&lt;/a&gt;. It’s much better to use &lt;a href=&quot;https://hackage.haskell.org/package/reflex-dom-core-0.4/docs/Reflex-Dom-Widget-Basic.html#v:dynText&quot;&gt;dynText&lt;/a&gt; and &lt;a href=&quot;https://hackage.haskell.org/package/reflex-dom-core-0.4/docs/Reflex-Dom-Widget-Basic.html#v:elDynAttr&quot;&gt;elDynAttr&lt;/a&gt; to modify the dom/layout. However, &lt;code&gt;widgetHold&lt;/code&gt; is really convenient to get access to values within events. I also think that the parts inside a widgetHold function don’t get evaluated until the event occurs. This is really convenient for login. Now you don’t have to evaluate the bulk of your app on initial page load. &lt;code&gt;widgetHold&lt;/code&gt; can postpone evaluating large parts of your app. Which makes that initial render much faster&lt;a href=&quot;#fn8&quot; class=&quot;footnote-ref&quot; id=&quot;fnref8&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;8&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Anyway as we can see from the type signature, in this case the &lt;code&gt;b ~ ()&lt;/code&gt;, and the &lt;code&gt;a ~ User&lt;/code&gt;. Which leads us to authenticatedWidget:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb18&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb18-1&quot;&gt;&lt;a href=&quot;#cb18-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;authenticatedWidget ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m ()&lt;/span&gt;
&lt;span id=&quot;cb18-2&quot;&gt;&lt;a href=&quot;#cb18-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;authenticatedWidget user &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-3&quot;&gt;&lt;a href=&quot;#cb18-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  el &lt;span class=&quot;st&quot;&gt;&amp;quot;div&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-4&quot;&gt;&lt;a href=&quot;#cb18-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    getUsersWidget&lt;/span&gt;
&lt;span id=&quot;cb18-5&quot;&gt;&lt;a href=&quot;#cb18-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    sendMsgWidget user&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is the same as the app discussed in the previous blog post. Although now we use the logged in user to send messages.&lt;/p&gt;
&lt;h1 id=&quot;xsrf&quot;&gt;XSRF&lt;/h1&gt;
&lt;p&gt;To make servant reflex work nicely with servant-auth we need to modify the requests a bit, servant reflex supports this with &lt;code&gt;ClientOptions&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb19&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb19-1&quot;&gt;&lt;a href=&quot;#cb19-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;clientOpts ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ClientOptions&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-2&quot;&gt;&lt;a href=&quot;#cb19-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;clientOpts &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ClientOptions&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; tweakReq&lt;/span&gt;
&lt;span id=&quot;cb19-3&quot;&gt;&lt;a href=&quot;#cb19-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-4&quot;&gt;&lt;a href=&quot;#cb19-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    tweakReq r &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-5&quot;&gt;&lt;a href=&quot;#cb19-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      mayCookie &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; findCookie cookieName&lt;/span&gt;
&lt;span id=&quot;cb19-6&quot;&gt;&lt;a href=&quot;#cb19-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; r &lt;span class=&quot;op&quot;&gt;&amp;amp;&lt;/span&gt; headerMod headerName &lt;span class=&quot;op&quot;&gt;.~&lt;/span&gt; mayCookie &lt;span class=&quot;co&quot;&gt;-- forgive lenses&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-7&quot;&gt;&lt;a href=&quot;#cb19-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    headerMod d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; xhrRequest_config &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; xhrRequestConfig_headers &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; at d&lt;/span&gt;
&lt;span id=&quot;cb19-8&quot;&gt;&lt;a href=&quot;#cb19-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-9&quot;&gt;&lt;a href=&quot;#cb19-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;apiClients ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; t m&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; _&lt;/span&gt;
&lt;span id=&quot;cb19-10&quot;&gt;&lt;a href=&quot;#cb19-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;apiClients &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; clientWithOpts&lt;/span&gt;
&lt;span id=&quot;cb19-11&quot;&gt;&lt;a href=&quot;#cb19-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	serviceAPI (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;m) (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;()) (constDyn url) clientOpts&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The client options lives in the &lt;code&gt;JSM&lt;/code&gt; monad and gives us an opportunity to modify the &lt;code&gt;XHRRequest&lt;/code&gt; how we want. We make sure the names are the same by using the ones defined in the common module.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;So there you have it. Authentication. Not the most exciting thing in the world, but once this is done you can start making something cool. I hope I helped you get trough this ordeal fast, and explain some of the finer reflex points. Now I hope to see many cool reflex projects popping up. PM me your cool projects.&lt;/p&gt;
&lt;h1 id=&quot;references&quot;&gt;References&lt;/h1&gt;
&lt;p&gt;With the release of reflex &lt;code&gt;0.5&lt;/code&gt; we now have updated docs!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jappeace/awesome-project-name/tree/auth&quot;&gt;Source code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;%7Bfilename%7D/fullstack-haskell-reflex-servant.md&quot;&gt;Previous blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hackage.haskell.org/package/reflex&quot;&gt;Reflex&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hackage.haskell.org/package/reflex-dom-core-0.4&quot;&gt;Reflex dom&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://hackage.haskell.org/package/servant-reflex-0.3.4&quot;&gt;Servant reflex&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.haskell.org/MonadFix&quot;&gt;MonadFix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://hackage.haskell.org/package/base-4.12.0.0/docs/Control-Monad-Fix.html&quot;&gt;Control.Monad.Fix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#the-recursive-do-notation&quot;&gt;Recursive do language extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://hackage.haskell.org/package/reflex-dom-core-0.4/docs/Reflex-Dom-Xhr.html&quot;&gt;Reflex dom XHR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;What I’m doing in production is a clear cache refres on any 4xx status code and decode/encoding errors. This automatically will fix any stale clients without any mental overhead. I just attach a monad to most api calls which does that.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;For completeness: The &lt;code&gt;userInput&lt;/code&gt; form returns a dynamic user, which is both a behavior as well as an event: the event fires whenever the behavior changes value.&lt;a href=&quot;#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;&lt;a href=&quot;http://hackage.haskell.org/package/base-4.12.0.0/docs/Control-Monad-Fix.html&quot;&gt;This&lt;/a&gt; explains how it works, note the thesis on value recursion too.&lt;a href=&quot;#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;I currently believe that in reflex the cycle can be broken because we start with the preposition that a dynamic and behavior always have a value. Even in this case we can just set it to empty, until the event fires, which is by definition after rendering. This also explains why you use a sampled value from a behavior in a &lt;code&gt;rec&lt;/code&gt; block.&lt;a href=&quot;#fnref4&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn5&quot;&gt;&lt;p&gt;sequence doesn’t work because event isn’t foldable, and it will never be foldable because that breaks FRP semantics.&lt;a href=&quot;#fnref5&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn6&quot;&gt;&lt;p&gt;And &lt;a href=&quot;https://hackage.haskell.org/package/reflex-dom-core-0.4/docs/Reflex-Dom-Widget-Basic.html#v:dyn&quot;&gt;dyn&lt;/a&gt; for that matter&lt;a href=&quot;#fnref6&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn7&quot;&gt;&lt;p&gt;Even though some &lt;a href=&quot;https://www.reddit.com/r/javascript/comments/6115ay/why_do_developers_think_the_dom_is_slow/&quot;&gt;reddit thread&lt;/a&gt; disagrees with me thinking the DOM is slow and saying it’s because of &lt;a href=&quot;https://gist.github.com/paulirish/5d52fb081b3570c81e3a&quot;&gt;layout trashing&lt;/a&gt;. Heretics.&lt;a href=&quot;#fnref7&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn8&quot;&gt;&lt;p&gt;I still think reflex load times are too slow, especially on mobile. I know about the app option, but an app is just a dirty hack to get your crappy website to speed up. It’s much better to have everything as a website, it results in less maintenance and better UX (if you can pull it off). Nobody should have to install anything in 2019. But the mobile web will remain slow for &lt;a href=&quot;https://www.youtube.com/watch?v=4bZvq3nodf4&quot;&gt;good reasons&lt;/a&gt; and if I knew how I’d happily help speeding up GHCJS and reflex. I think for example that widgetHold and dyn may be a good candidates for code splitting entry points. But I believe you’d need to make the compiler aware of that somehow. I also believe you probably don’t need the entire Haskell runtime immediately, lazily loading exceptions would be good for example.&lt;a href=&quot;#fnref8&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Lens into wrapped newtypes</title>
    <link href="https://jappieklooster.nl/lens-into-wrapped-newtypes.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2018-12-30:/lens-into-wrapped-newtypes.html</id>
    <published>2018-12-30T21:34:00Z</published>
    <updated>2018-12-30T21:34:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="technique"/>
    <summary type="html">&lt;figure&gt;
&lt;img src=&quot;/images/2018/nt-iso.svg&quot; alt=&quot;Categorical representation of the NT iso&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Categorical representation of the NT iso&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;blockquote&gt;
&lt;p&gt;All newtypes are isomorphisms&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;– My mother&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;http://hackage.haskell.org/package/lens-4.17/docs/Control-Lens-Wrapped.html&quot;&gt;Control.Lens.Wrapped&lt;/a&gt; uses the isomorphism property to introduce a type class &lt;code&gt;Wrapped&lt;/code&gt;. Let’s explore use cases, because after all, it doesn’t appear to do much at first glance. What’s the point of formalizing wrapping and unwrapping of&lt;/p&gt;</summary>
    <content type="html">&lt;figure&gt;
&lt;img src=&quot;/images/2018/nt-iso.svg&quot; alt=&quot;Categorical representation of the NT iso&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Categorical representation of the NT iso&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;blockquote&gt;
&lt;p&gt;All newtypes are isomorphisms&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;– My mother&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;http://hackage.haskell.org/package/lens-4.17/docs/Control-Lens-Wrapped.html&quot;&gt;Control.Lens.Wrapped&lt;/a&gt; uses the isomorphism property to introduce a type class &lt;code&gt;Wrapped&lt;/code&gt;. Let’s explore use cases, because after all, it doesn’t appear to do much at first glance. What’s the point of formalizing wrapping and unwrapping of types?&lt;/p&gt;
&lt;p&gt;Instance boilerplate will be reduced in this blog post. In my use case this will include orphan instances. Furthermore, I believe that this technique will make using newtypes more attractive.&lt;/p&gt;
&lt;h1 id=&quot;newtype&quot;&gt;Newtype&lt;/h1&gt;
&lt;p&gt;Consider the following common code in a &lt;a href=&quot;%7Bfilename%7D/fullstack-haskell-reflex-servant.md&quot;&gt;fullstack haskell webapp&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Login&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Login&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	{&lt;span class=&quot;ot&quot;&gt; email ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	,&lt;span class=&quot;ot&quot;&gt; password ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Looks good? No of course not. This common code is shared between both client and server, therefore we should be pendantic about these record field. We wrap common occurrences such as Text in newtypes so we don’t accidentally mix up the fields. This would be a better representation:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt; {&lt;span class=&quot;ot&quot;&gt; unEmail ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; }&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt; {&lt;span class=&quot;ot&quot;&gt; unPassword ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; }&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;#cb2-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;#cb2-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Login&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Login&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;#cb2-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	{&lt;span class=&quot;ot&quot;&gt; email ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;#cb2-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	,&lt;span class=&quot;ot&quot;&gt; password ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;#cb2-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Of course this extra safety comes at the cost of more boilerplate, but these few lines add a lot of safety: Mixing of email and password becomes less likely, from frontend input to the backend. This is analogous to having integration tests on user input fields, AJAX calls, HTTP endpoints, and database insertion. That’s a lot of safety for two extra lines, therefore we accept this trade and move on.&lt;/p&gt;
&lt;h1 id=&quot;database&quot;&gt;Database&lt;/h1&gt;
&lt;p&gt;Now we can put the fields of login directly into our user table schema for the database:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- database&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;#cb3-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;#cb3-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	{&lt;span class=&quot;ot&quot;&gt; email ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;#cb3-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	,&lt;span class=&quot;ot&quot;&gt; password ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-5&quot;&gt;&lt;a href=&quot;#cb3-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	}&lt;/span&gt;
&lt;span id=&quot;cb3-6&quot;&gt;&lt;a href=&quot;#cb3-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	&lt;span class=&quot;co&quot;&gt;-- etc beam boilerplate...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Although this is what we want, it doesn’t compile, we need to tell beam how to get the right underlying type so it can produce the right queries and schema:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;#cb4-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- backend orphanage&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;#cb4-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasSqlEqualityCheck&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgExpressionSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This instance allows us to use the &lt;a href=&quot;http://hackage.haskell.org/package/beam-core-0.7.2.2/docs/Database-Beam-Query.html#v:-61--61-.&quot;&gt;&lt;code&gt;==.&lt;/code&gt;&lt;/a&gt; operator on beam expressions directly. We can now compare the column email with a client email. I don’t know why an instance is needed for this, but the compiler wanted it whenever I used that operator.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- backend orphanage&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;#cb5-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasSqlValueSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgValueSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-3&quot;&gt;&lt;a href=&quot;#cb5-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  sqlValueSyntax &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sqlValueSyntax &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; unEmail&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we use &lt;code&gt;unEmail&lt;/code&gt; to the underlying type their sqlValuesyntax.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;#cb6-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- backend orphanage&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;#cb6-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromBackendRow&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Postgres&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I believe this tells beam we want to be able to use a postgres database on email. We don’t have to instantiate sqlite instances (beam can do multiple backends).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;#cb7-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- backend orphanage&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;#cb7-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromField&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;#cb7-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  fromField a b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; fromField a b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://hackage.haskell.org/package/postgresql-simple-0.5.4.0/docs/Database-PostgreSQL-Simple-FromField.html#t:FromField&quot;&gt;FromField&lt;/a&gt; is a type class from &lt;a href=&quot;https://hackage.haskell.org/package/postgresql-simple-0.5.4.0/docs/Database-PostgreSQL-Simple.html&quot;&gt;PgSimple&lt;/a&gt;. Here, we’re telling the compiler to just use the from field from the underlying type, and once it’s done we can wrap it back into an email.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;#cb8-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- backend orphanage&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;#cb8-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasDefaultSqlDataTypeConstraints&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgColumnSchemaSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is a constraint coming from beam migrate, if you want to have automatic schema generation, or be able to step trough various schemas you need this.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;#cb9-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- backend orphanage&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;#cb9-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasDefaultSqlDataType&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgDataTypeSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;#cb9-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  defaultSqlDataType proxy &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; defaultSqlDataType &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; unEmail &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; proxy&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is also needed for migrations. Here we’re removing the newtype from the proxy to tell it to use the underlying type. Note that a proxy isn’t holding any data, those functions will never be executed, in case of proxies we’re just interested in type.&lt;/p&gt;
&lt;p&gt;All of this is repeated for Password to, and any other newtypes you want:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;#cb10-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- backend orphanage&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;#cb10-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasSqlEqualityCheck&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgExpressionSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;#cb10-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasSqlValueSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgValueSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-4&quot;&gt;&lt;a href=&quot;#cb10-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  sqlValueSyntax &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sqlValueSyntax &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; unPassword&lt;/span&gt;
&lt;span id=&quot;cb10-5&quot;&gt;&lt;a href=&quot;#cb10-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromBackendRow&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Postgres&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-6&quot;&gt;&lt;a href=&quot;#cb10-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromField&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-7&quot;&gt;&lt;a href=&quot;#cb10-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  fromField a b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; fromField a b&lt;/span&gt;
&lt;span id=&quot;cb10-8&quot;&gt;&lt;a href=&quot;#cb10-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasDefaultSqlDataTypeConstraints&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgColumnSchemaSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-9&quot;&gt;&lt;a href=&quot;#cb10-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasDefaultSqlDataType&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgDataTypeSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-10&quot;&gt;&lt;a href=&quot;#cb10-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  defaultSqlDataType proxy &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; defaultSqlDataType &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; unPassword &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; proxy&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I put these instances into an orphanage (dedicated file for orphan instances) because I want to put the newtypes directly into the database. However I don’t want our common code to be dependent on beam, that would mean the frontend JavaScript suddenly would pull in beam as a dependency for no reason. We’ll eliminate the need for these orphans later.&lt;/p&gt;
&lt;p&gt;What did we gain? The ability to put these newtypes in the database, what did we lose? Well we now have a lot of extra boilerplate to content with.&lt;/p&gt;
&lt;h1 id=&quot;wrapped&quot;&gt;Wrapped&lt;/h1&gt;
&lt;p&gt;Let’s kill the boilerplate!&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb11&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb11-1&quot;&gt;&lt;a href=&quot;#cb11-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- common&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-2&quot;&gt;&lt;a href=&quot;#cb11-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt; {&lt;span class=&quot;ot&quot;&gt; unEmail ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; } &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-3&quot;&gt;&lt;a href=&quot;#cb11-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt; {&lt;span class=&quot;ot&quot;&gt; unPassword ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; } &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-4&quot;&gt;&lt;a href=&quot;#cb11-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-5&quot;&gt;&lt;a href=&quot;#cb11-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Wrapped&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-6&quot;&gt;&lt;a href=&quot;#cb11-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Wrapped&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you can provide an &lt;a href=&quot;http://hackage.haskell.org/package/lens-4.17/docs/Control-Lens-Iso.html#t:Iso-39-&quot;&gt;Iso’&lt;/a&gt;, then you instantiate the Wrapped type class. If a newtype has derived generic we get an instance for free by just declaring it, and using the default. This is possible because generic knows about constructors.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;#cb12-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- backend orphanage&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-2&quot;&gt;&lt;a href=&quot;#cb12-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;wrappedSqlValueSyntax  ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Wrapped&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;HasSqlValueSyntax&lt;/span&gt; b (&lt;span class=&quot;dt&quot;&gt;Unwrapped&lt;/span&gt; a)) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; b&lt;/span&gt;
&lt;span id=&quot;cb12-3&quot;&gt;&lt;a href=&quot;#cb12-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;wrappedSqlValueSyntax  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sqlValueSyntax &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; view _Wrapped&amp;#39;&lt;/span&gt;
&lt;span id=&quot;cb12-4&quot;&gt;&lt;a href=&quot;#cb12-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-5&quot;&gt;&lt;a href=&quot;#cb12-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;fromWrappedField ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Wrapped&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;FromField&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Unwrapped&lt;/span&gt; a)) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FieldParser&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb12-6&quot;&gt;&lt;a href=&quot;#cb12-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;fromWrappedField a b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; review _Wrapped&amp;#39; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; fromField a b&lt;/span&gt;
&lt;span id=&quot;cb12-7&quot;&gt;&lt;a href=&quot;#cb12-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-8&quot;&gt;&lt;a href=&quot;#cb12-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;wrappedDefaultSqlDataType ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Wrapped&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;HasDefaultSqlDataType&lt;/span&gt; b (&lt;span class=&quot;dt&quot;&gt;Unwrapped&lt;/span&gt; a)) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; b&lt;/span&gt;
&lt;span id=&quot;cb12-9&quot;&gt;&lt;a href=&quot;#cb12-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;wrappedDefaultSqlDataType proxy &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; defaultSqlDataType &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; view _Wrapped&amp;#39; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; proxy&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These functions pull out the essence of wrapping. If &lt;code&gt;a&lt;/code&gt; is wrapped, we can speak about it’s unwrapped form (which is why we need the type class). If &lt;code&gt;a&lt;/code&gt; his unwrapped form for example implements &lt;code&gt;FromField&lt;/code&gt;, we can make a &lt;code&gt;FieldParser&lt;/code&gt; for it.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb13&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb13-1&quot;&gt;&lt;a href=&quot;#cb13-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- backend orphanage&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-2&quot;&gt;&lt;a href=&quot;#cb13-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasSqlEqualityCheck&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgExpressionSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-3&quot;&gt;&lt;a href=&quot;#cb13-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasSqlValueSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgValueSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-4&quot;&gt;&lt;a href=&quot;#cb13-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  sqlValueSyntax &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; wrappedSqlValueSyntax&lt;/span&gt;
&lt;span id=&quot;cb13-5&quot;&gt;&lt;a href=&quot;#cb13-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromBackendRow&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Postgres&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-6&quot;&gt;&lt;a href=&quot;#cb13-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromField&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-7&quot;&gt;&lt;a href=&quot;#cb13-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  fromField &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; fromWrappedField&lt;/span&gt;
&lt;span id=&quot;cb13-8&quot;&gt;&lt;a href=&quot;#cb13-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasDefaultSqlDataTypeConstraints&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgColumnSchemaSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-9&quot;&gt;&lt;a href=&quot;#cb13-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasDefaultSqlDataType&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgDataTypeSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-10&quot;&gt;&lt;a href=&quot;#cb13-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  defaultSqlDataType &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; wrappedDefaultSqlDataType&lt;/span&gt;
&lt;span id=&quot;cb13-11&quot;&gt;&lt;a href=&quot;#cb13-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-12&quot;&gt;&lt;a href=&quot;#cb13-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasSqlEqualityCheck&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgExpressionSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-13&quot;&gt;&lt;a href=&quot;#cb13-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasSqlValueSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgValueSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-14&quot;&gt;&lt;a href=&quot;#cb13-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  sqlValueSyntax &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; wrappedSqlValueSyntax&lt;/span&gt;
&lt;span id=&quot;cb13-15&quot;&gt;&lt;a href=&quot;#cb13-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromBackendRow&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Postgres&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-16&quot;&gt;&lt;a href=&quot;#cb13-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromField&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-17&quot;&gt;&lt;a href=&quot;#cb13-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  fromField &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; fromWrappedField&lt;/span&gt;
&lt;span id=&quot;cb13-18&quot;&gt;&lt;a href=&quot;#cb13-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasDefaultSqlDataTypeConstraints&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgColumnSchemaSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-19&quot;&gt;&lt;a href=&quot;#cb13-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;HasDefaultSqlDataType&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgDataTypeSyntax&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-20&quot;&gt;&lt;a href=&quot;#cb13-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  defaultSqlDataType &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; wrappedDefaultSqlDataType&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The instances themselves do the same thing over and over, they wrap or unwrap types to get the underlying interesting value. Here this is obvious by having the instances of both Email and Password point to the same functions.&lt;/p&gt;
&lt;p&gt;At first glance, this implementation does not look better. However we now can clearly see that the wrapping is indeed the same operation because the instances all point toward the same functions. The FromField instance for Password is implemented with fromWrappedField, so does the Email instance. This is possible because both Email and Password have instantiated the Wrapped instance.&lt;/p&gt;
&lt;p&gt;This change is a lot better if you consider that there is no more logic being repeated here. Which means there are no more logic bugs in the repetition. The boilerplate is now in it’s purest form: Dumb repetition. By itself I wouldn’t consider the current state to be that bad anymore. However, these are still orphans, which can cause &lt;a href=&quot;https://stackoverflow.com/questions/3079537/orphaned-instances-in-haskell&quot;&gt;bad problems&lt;/a&gt;. We should kill all orphans!&lt;/p&gt;
&lt;h1 id=&quot;a-general-instance&quot;&gt;A general instance&lt;/h1&gt;
&lt;p&gt;Can’t we make a generalized instance that does all of this wrapping for all newtypes? My first attempt was rather crazy looking back. I wanted to create the ultimate orphan. a polymorphic instance that was kept in check by constraints such as &lt;code&gt;Wrapped&lt;/code&gt; and the fact underlying types would have these beam instances implemented. I attempted this but did got very far, I wasn’t very sure what was going on anymore with the type errors I got out of that. But after a bit of searching I realized that what I attempted to do was ridiculous and dangerous. Of course that wouldn’t work, now all previous and future &lt;code&gt;Wrapped&lt;/code&gt; newtypes would have to be able to be fit into postgres or fail. This piece of code would break all existing libraries that would’ve had a &lt;code&gt;Wrapped&lt;/code&gt; newtype. No this was an absurd idea.&lt;/p&gt;
&lt;p&gt;Rather than solving the problem for all newtypes, I stepped back, and added yet another newtype:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb14-1&quot;&gt;&lt;a href=&quot;#cb14-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- wrapped.hs&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-2&quot;&gt;&lt;a href=&quot;#cb14-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DBFieldWrap&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DBFieldWrap&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-3&quot;&gt;&lt;a href=&quot;#cb14-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; _unField ::&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb14-4&quot;&gt;&lt;a href=&quot;#cb14-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  } &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb14-5&quot;&gt;&lt;a href=&quot;#cb14-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-6&quot;&gt;&lt;a href=&quot;#cb14-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Wrapped&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Wrapped&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;DBFieldWrap&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb14-7&quot;&gt;&lt;a href=&quot;#cb14-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Wrapped&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;BeamBackend&lt;/span&gt; be,&lt;/span&gt;
&lt;span id=&quot;cb14-8&quot;&gt;&lt;a href=&quot;#cb14-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;dt&quot;&gt;BackendFromField&lt;/span&gt; be (&lt;span class=&quot;dt&quot;&gt;DBFieldWrap&lt;/span&gt; a),&lt;/span&gt;
&lt;span id=&quot;cb14-9&quot;&gt;&lt;a href=&quot;#cb14-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;dt&quot;&gt;FromBackendRow&lt;/span&gt; be (&lt;span class=&quot;dt&quot;&gt;Unwrapped&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb14-10&quot;&gt;&lt;a href=&quot;#cb14-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         ) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-11&quot;&gt;&lt;a href=&quot;#cb14-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         &lt;span class=&quot;dt&quot;&gt;FromBackendRow&lt;/span&gt; be (&lt;span class=&quot;dt&quot;&gt;DBFieldWrap&lt;/span&gt; a)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That final instance shows the core idea. We add the wrapped restriction on &lt;code&gt;a&lt;/code&gt;, which allows us to speak about the unwrapped form of &lt;code&gt;a&lt;/code&gt;. The unwrapped type of &lt;code&gt;Email&lt;/code&gt; would be Text. Beam has already made a FromField instance for Text, so we’re done.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb15&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb15-1&quot;&gt;&lt;a href=&quot;#cb15-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; ( &lt;span class=&quot;dt&quot;&gt;IsSql92ExpressionSyntax&lt;/span&gt; be&lt;/span&gt;
&lt;span id=&quot;cb15-2&quot;&gt;&lt;a href=&quot;#cb15-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         , &lt;span class=&quot;dt&quot;&gt;Wrapped&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb15-3&quot;&gt;&lt;a href=&quot;#cb15-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         , &lt;span class=&quot;dt&quot;&gt;HasSqlEqualityCheck&lt;/span&gt; be (&lt;span class=&quot;dt&quot;&gt;Unwrapped&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb15-4&quot;&gt;&lt;a href=&quot;#cb15-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         ) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-5&quot;&gt;&lt;a href=&quot;#cb15-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         &lt;span class=&quot;dt&quot;&gt;HasSqlEqualityCheck&lt;/span&gt; be (&lt;span class=&quot;dt&quot;&gt;DBFieldWrap&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb15-6&quot;&gt;&lt;a href=&quot;#cb15-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-7&quot;&gt;&lt;a href=&quot;#cb15-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Wrapped&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;FromField&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Unwrapped&lt;/span&gt; a)) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromField&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;DBFieldWrap&lt;/span&gt; a) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-8&quot;&gt;&lt;a href=&quot;#cb15-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  fromField a b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; review (_Wrapped&amp;#39; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; _Wrapped&amp;#39;) &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; fromField a b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;a href=&quot;http://hackage.haskell.org/package/lens-4.17/docs/Control-Lens-Review.html#v:review&quot;&gt;review function&lt;/a&gt; just calls the constructor. We have to call two &lt;code&gt;_Wrapped&apos;&lt;/code&gt;s with it because we need to put it in the &lt;code&gt;Email&lt;/code&gt; or &lt;code&gt;Password&lt;/code&gt;, and then we need to put it into the &lt;code&gt;DBField&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb16&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb16-1&quot;&gt;&lt;a href=&quot;#cb16-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Wrapped&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;HasSqlValueSyntax&lt;/span&gt; be (&lt;span class=&quot;dt&quot;&gt;Unwrapped&lt;/span&gt; a)) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-2&quot;&gt;&lt;a href=&quot;#cb16-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         &lt;span class=&quot;dt&quot;&gt;HasSqlValueSyntax&lt;/span&gt; be (&lt;span class=&quot;dt&quot;&gt;DBFieldWrap&lt;/span&gt; a) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-3&quot;&gt;&lt;a href=&quot;#cb16-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  sqlValueSyntax &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sqlValueSyntax &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; view (_Wrapped&amp;#39; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; _Wrapped&amp;#39;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The view function is just an alias for &lt;code&gt;^.&lt;/code&gt;, a getter. We get the result of wrapping twice.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb17&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb17-1&quot;&gt;&lt;a href=&quot;#cb17-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; ( &lt;span class=&quot;dt&quot;&gt;IsSql92ColumnSchemaSyntax&lt;/span&gt; be&lt;/span&gt;
&lt;span id=&quot;cb17-2&quot;&gt;&lt;a href=&quot;#cb17-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         , &lt;span class=&quot;dt&quot;&gt;Wrapped&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb17-3&quot;&gt;&lt;a href=&quot;#cb17-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         , &lt;span class=&quot;dt&quot;&gt;HasDefaultSqlDataTypeConstraints&lt;/span&gt; be (&lt;span class=&quot;dt&quot;&gt;Unwrapped&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb17-4&quot;&gt;&lt;a href=&quot;#cb17-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         ) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-5&quot;&gt;&lt;a href=&quot;#cb17-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         &lt;span class=&quot;dt&quot;&gt;HasDefaultSqlDataTypeConstraints&lt;/span&gt; be (&lt;span class=&quot;dt&quot;&gt;DBFieldWrap&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb17-6&quot;&gt;&lt;a href=&quot;#cb17-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-7&quot;&gt;&lt;a href=&quot;#cb17-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; ( &lt;span class=&quot;dt&quot;&gt;IsSql92DataTypeSyntax&lt;/span&gt; be&lt;/span&gt;
&lt;span id=&quot;cb17-8&quot;&gt;&lt;a href=&quot;#cb17-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         , &lt;span class=&quot;dt&quot;&gt;Wrapped&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb17-9&quot;&gt;&lt;a href=&quot;#cb17-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         , &lt;span class=&quot;dt&quot;&gt;HasDefaultSqlDataType&lt;/span&gt; be (&lt;span class=&quot;dt&quot;&gt;Unwrapped&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb17-10&quot;&gt;&lt;a href=&quot;#cb17-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         ) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-11&quot;&gt;&lt;a href=&quot;#cb17-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         &lt;span class=&quot;dt&quot;&gt;HasDefaultSqlDataType&lt;/span&gt; be (&lt;span class=&quot;dt&quot;&gt;DBFieldWrap&lt;/span&gt; a) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-12&quot;&gt;&lt;a href=&quot;#cb17-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  defaultSqlDataType proxy &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-13&quot;&gt;&lt;a href=&quot;#cb17-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    defaultSqlDataType &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; view (_Wrapped&amp;#39; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; _Wrapped&amp;#39;) &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; proxy&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Apparently you can &lt;code&gt;fmap&lt;/code&gt; into a proxy to get the right type out. Even though a proxy has no data, it will change type.&lt;/p&gt;
&lt;p&gt;This does exactly the same thing as the independent functions did in case of the orphanage, the only difference is that they wrap twice. We essentially tell the type checker to look for the beam instance two levels deeper. We tell it by using restrictions on the instances (the stuff before &lt;code&gt;=&amp;gt;&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Now we can insert our newtypes directly into database without having to implement all those Beam instances:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb18&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb18-1&quot;&gt;&lt;a href=&quot;#cb18-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- database&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-2&quot;&gt;&lt;a href=&quot;#cb18-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb18-3&quot;&gt;&lt;a href=&quot;#cb18-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	{&lt;span class=&quot;ot&quot;&gt; email ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f (&lt;span class=&quot;dt&quot;&gt;DBFieldWrap&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb18-4&quot;&gt;&lt;a href=&quot;#cb18-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	,&lt;span class=&quot;ot&quot;&gt; password ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f (&lt;span class=&quot;dt&quot;&gt;DBFieldWrap&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb18-5&quot;&gt;&lt;a href=&quot;#cb18-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	}&lt;/span&gt;
&lt;span id=&quot;cb18-6&quot;&gt;&lt;a href=&quot;#cb18-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	&lt;span class=&quot;co&quot;&gt;-- etc beam boilerplate...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Adding an additional newtype for the database is now easy:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb19&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb19-1&quot;&gt;&lt;a href=&quot;#cb19-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- common&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-2&quot;&gt;&lt;a href=&quot;#cb19-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DateOfBirth&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DateOfBirth&lt;/span&gt; {&lt;span class=&quot;ot&quot;&gt; unEmail ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Day&lt;/span&gt; } &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-3&quot;&gt;&lt;a href=&quot;#cb19-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Wrapped&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DateOfBirth&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb19-4&quot;&gt;&lt;a href=&quot;#cb19-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-5&quot;&gt;&lt;a href=&quot;#cb19-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb19-6&quot;&gt;&lt;a href=&quot;#cb19-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	{&lt;span class=&quot;ot&quot;&gt; email ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f (&lt;span class=&quot;dt&quot;&gt;DBFieldWrap&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Email&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb19-7&quot;&gt;&lt;a href=&quot;#cb19-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	,&lt;span class=&quot;ot&quot;&gt; password ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f (&lt;span class=&quot;dt&quot;&gt;DBFieldWrap&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Password&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb19-8&quot;&gt;&lt;a href=&quot;#cb19-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	,&lt;span class=&quot;ot&quot;&gt; dob ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f (&lt;span class=&quot;dt&quot;&gt;DBFieldWrap&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DateOfBirth&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb19-9&quot;&gt;&lt;a href=&quot;#cb19-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that this technique doesn’t just work for beam instances, one could do the same for Aeson, or any other library that requires many instances on newtypes. The &lt;code&gt;Wrapped&lt;/code&gt; instance can be re-used.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;So what did we gain?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We no longer have orphans!&lt;/li&gt;
&lt;li&gt;Boilerplate has been reduced to just the wrapped instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What did we lose?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unfortunately we need to unwrap and wrap at the call sites (beam queries).&lt;/li&gt;
&lt;li&gt;To use this we need to depend on lens.&lt;/li&gt;
&lt;li&gt;The beam schema is a little bit more verbose.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because all those negative points are really small, I’m calling this a win. The sources can be found on &lt;a href=&quot;https://github.com/jappeace/dbfield&quot;&gt;github&lt;/a&gt; and &lt;a href=&quot;https://hackage.haskell.org/package/beam-newtype-field&quot;&gt;hackage&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Fullstack Haskell: Reflex and Servant</title>
    <link href="https://jappieklooster.nl/fullstack-haskell-reflex-and-servant.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2018-10-09:/fullstack-haskell-reflex-and-servant.html</id>
    <published>2018-10-09T12:08:00Z</published>
    <updated>2018-10-09T12:08:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;In the &lt;a href=&quot;/tag/pragmatic-haskell.html&quot;&gt;pragmatic haskell&lt;/a&gt; series, we saw how to setup a simple webserver with database. But at some point you still need a frontend. If it were 2005 you may have been able to get away with just &lt;a href=&quot;http://hackage.haskell.org/package/blaze-html&quot;&gt;blaze&lt;/a&gt;. But we are in 2018+, and &lt;a href=&quot;https://wiki.haskell.org/The_JavaScript_Problem&quot;&gt;JavaScript is a problem&lt;/a&gt;&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;In the &lt;a href=&quot;/tag/pragmatic-haskell.html&quot;&gt;pragmatic haskell&lt;/a&gt; series, we saw how to setup a simple webserver with database. But at some point you still need a frontend. If it were 2005 you may have been able to get away with just &lt;a href=&quot;http://hackage.haskell.org/package/blaze-html&quot;&gt;blaze&lt;/a&gt;. But we are in 2018+, and &lt;a href=&quot;https://wiki.haskell.org/The_JavaScript_Problem&quot;&gt;JavaScript is a problem&lt;/a&gt;. In this blog post we will explore how to deal with JavaScript trough reflex and GHCJS. An alternative to consider is &lt;a href=&quot;https://github.com/dmjio/miso&quot;&gt;miso&lt;/a&gt;, which uses the &lt;a href=&quot;https://guide.elm-lang.org/architecture/&quot;&gt;elm architecture&lt;/a&gt; (or &lt;a href=&quot;https://redux.js.org/&quot;&gt;redux&lt;/a&gt; if you’re from JS), here is a &lt;a href=&quot;https://www.reddit.com/r/haskell/comments/7nxni9/reflexdom_vs_miso/&quot;&gt;comparison&lt;/a&gt;. Obviously I chose reflex.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2018/reflex-and-servant.svg&quot; alt=&quot;fancy db image&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;fancy db image&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1 id=&quot;preparation&quot;&gt;Preparation&lt;/h1&gt;
&lt;p&gt;First we need to setup the dev environment. This time we’ll double down on &lt;a href=&quot;https://nixos.org/nix/&quot;&gt;nix&lt;/a&gt; because reflex does that too and fighting build tools is no fun. This has the advantage that the &lt;a href=&quot;https://github.com/jappeace/awesome-project-name/tree/reflex&quot;&gt;resulting code on github&lt;/a&gt; is reproducible. All need to be done is setup the file watch for which I wrote a make command:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;make&lt;/span&gt; file-watch&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This rebuilds both the Haskell back end and JavaScript front end incrementally.&lt;/p&gt;
&lt;p&gt;There are two separate environments now, one is for the native Haskell target (x86), and the other is the JavaScript target. We can enter the shell environment for the native target with &lt;code&gt;make enter&lt;/code&gt; and the JavaScript target with &lt;code&gt;make enter-js&lt;/code&gt;. This is convenient for doing one of commands.&lt;/p&gt;
&lt;p&gt;The biggest issue I had when setting this up was figuring out how to add extra dependencies not in the nix repo. I found out by reading the nix code that this can be done with the overrides flag. Another issue was tools for shells, such as hpack which generates cabal files from the &lt;code&gt;package.yaml&lt;/code&gt; file. I really wanted to use that as I didn’t want to learn cabal, besides, hpack’s is much more succinct, it doesn’t require explicit module exports. there is a shellOverrides attribute for that.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode nix&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    overrides = &lt;span class=&quot;va&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;rec&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;beam-core&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; self&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;callPackage &lt;span class=&quot;ss&quot;&gt;./packages/beam-core.nix&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;#cb2-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	  ...&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;#cb2-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;;&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;#cb2-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;	&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;..&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;#cb2-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    shellToolOverrides = &lt;span class=&quot;va&quot;&gt;ghc&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;#cb2-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;inherit&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;ghc&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;hpack&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-8&quot;&gt;&lt;a href=&quot;#cb2-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;fswatcher&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;inotify&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;tools&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-9&quot;&gt;&lt;a href=&quot;#cb2-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;		...&lt;/span&gt;
&lt;span id=&quot;cb2-10&quot;&gt;&lt;a href=&quot;#cb2-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1 id=&quot;back-end&quot;&gt;Back end&lt;/h1&gt;
&lt;p&gt;The backend is mostly the same as the result of the &lt;a href=&quot;/pragmatic-haskell.html&quot;&gt;pragmatic haskell&lt;/a&gt; series. We moved the API endpoints that need to be accessed by client to the e common code, and added an additional endpoint for hosting the html. Normally we wouldn’t use Haskell to deliver static assets and use a specialized program such as &lt;a href=&quot;https://www.nginx.com/&quot;&gt;nginx&lt;/a&gt;. Since this is for experimentation however we made an exception:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Webservice&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ServiceAPI&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;#cb3-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Raw&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- JS entry point&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;#cb3-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;#cb3-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;webservice ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Webservice&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-5&quot;&gt;&lt;a href=&quot;#cb3-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;webservice &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-6&quot;&gt;&lt;a href=&quot;#cb3-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-7&quot;&gt;&lt;a href=&quot;#cb3-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;...&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb3-8&quot;&gt;&lt;a href=&quot;#cb3-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-9&quot;&gt;&lt;a href=&quot;#cb3-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;server ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Webservice&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-10&quot;&gt;&lt;a href=&quot;#cb3-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;server conn&lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-11&quot;&gt;&lt;a href=&quot;#cb3-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (&lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; users &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; messages conn) &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; serveDirectoryFileServer &lt;span class=&quot;st&quot;&gt;&amp;quot;dist-ghcjs/build/x86_64-linux/ghcjs-0.2.1/frontend-0.1.0.0/c/webservice/build/webservice/webservice.jsexe/&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The webservice type definition has the aditional &lt;code&gt;Raw&lt;/code&gt; endpoint, which &lt;a href=&quot;http://haskell-servant.github.io/servant/Servant-API-Raw.html&quot;&gt;allows hosting&lt;/a&gt; of custom wai apps. The &lt;code&gt;serveDirectoryFileServer&lt;/code&gt; is that custom wai app and just hosts the JavaScript output of the client.&lt;/p&gt;
&lt;h1 id=&quot;common-code&quot;&gt;Common code&lt;/h1&gt;
&lt;p&gt;This is where the shared code between client and server lives. We put the API definition in here. Since servant can create both servers and clients it’s a great library for this use case.&lt;/p&gt;
&lt;p&gt;Any change in API will now cause the type checker to tell us where this is affected in both client and server. Type safety becomes amplified, making bugs more obvious and increasing developer productivity.&lt;/p&gt;
&lt;p&gt;The actual &lt;a href=&quot;#commonsrccommonhs&quot;&gt;content&lt;/a&gt; of this module isn’t that interesting, it’s just the API definition. Common code gets compiled within the JavaScript client. This means it’s public, one should not put any passwords or trade secrets in here.&lt;/p&gt;
&lt;h1 id=&quot;front-end&quot;&gt;Front end&lt;/h1&gt;
&lt;p&gt;I started with trying to get reflex to work with servant because it seemed the most uncertain. After this I intended to use &lt;code&gt;servant-client&lt;/code&gt; for generating the client functions, here I ran into another hurdle as the latest servant wasn’t available. Apparently reflex is pinned to an old hackage repository, I attempted to upgrade but abandoned that endeavour as it required more nix modifications and I’d prefer to keep the same pin as upstream so I could get help when I needed it. Using the older servant, I hit a run time exception:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;uncaught exception in Haskell main thread: ReferenceError: h$hsnet_getaddrinfo is not defined&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is because servant client uses a system call for networking which is unavailable in the browser sandbox. A bit of googling led me to &lt;a href=&quot;https://github.com/imalsogreg/servant-reflex&quot;&gt;servant reflex&lt;/a&gt;. Using this was hard because are no official &lt;a href=&quot;http://hackage.haskell.org/package/servant-reflex-0.3.3/candidate&quot;&gt;haddocs&lt;/a&gt; since it hasn’t been released yet. Finding an &lt;a href=&quot;https://github.com/meditans/haskell-webapps/tree/master/UI/ReflexFRP/mockLoginPage&quot;&gt;example&lt;/a&gt; was of great help which led me to this client definition:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;apiClients ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; t m&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; _&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;#cb5-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;apiClients &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; client serviceAPI (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;m) (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;()) (constDyn url)&lt;/span&gt;
&lt;span id=&quot;cb5-3&quot;&gt;&lt;a href=&quot;#cb5-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; url ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;BaseUrl&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-4&quot;&gt;&lt;a href=&quot;#cb5-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        url &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;BasePath&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This creates both functions for querying the &lt;code&gt;serviceAPI&lt;/code&gt; from the common module. All this seems to do is getting that &lt;code&gt;m&lt;/code&gt; in scope and applying it to the client with a proxy. The partial type signature was left from the example this way intentionally, because it’s formalized below anyway and it’s rather big.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;#cb6-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;getUsers ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;#cb6-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t ()&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;#cb6-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;ReqResult&lt;/span&gt; () [&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;]))&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;#cb6-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;postMessage ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;#cb6-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text.Text&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb6-6&quot;&gt;&lt;a href=&quot;#cb6-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t ()&lt;/span&gt;
&lt;span id=&quot;cb6-7&quot;&gt;&lt;a href=&quot;#cb6-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;ReqResult&lt;/span&gt; () [&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;]))&lt;/span&gt;
&lt;span id=&quot;cb6-8&quot;&gt;&lt;a href=&quot;#cb6-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(getUsers &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; postMessage) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; apiClients&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This pulls out the functions from &lt;code&gt;apiClients&lt;/code&gt;, we also get there final signature here. The entire file can be seen in the &lt;a href=&quot;#frontendsrcservantclienths&quot;&gt;sources&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;reflex&quot;&gt;Reflex&lt;/h2&gt;
&lt;p&gt;After getting the API to function I started working on making an actual UI. Which is what this code does for the &lt;code&gt;getUsers&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;#cb7-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;reflex ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt;()&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;#cb7-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;reflex &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;#cb7-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  mainWidget &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;#cb7-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    el &lt;span class=&quot;st&quot;&gt;&amp;quot;div&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-5&quot;&gt;&lt;a href=&quot;#cb7-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;co&quot;&gt;-- babys steps, get users from memory&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-6&quot;&gt;&lt;a href=&quot;#cb7-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        intButton  &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; button &lt;span class=&quot;st&quot;&gt;&amp;quot;Get Users&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-7&quot;&gt;&lt;a href=&quot;#cb7-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        serverInts &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; fmapMaybe reqSuccess &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; getUsers intButton&lt;/span&gt;
&lt;span id=&quot;cb7-8&quot;&gt;&lt;a href=&quot;#cb7-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        display &lt;span class=&quot;op&quot;&gt;=&amp;lt;&amp;lt;&lt;/span&gt; holdDyn ([&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;none&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;none&amp;quot;&lt;/span&gt;]) serverInts&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;mainWidget is the root of reflex, we use &lt;code&gt;el&lt;/code&gt; to specify HTML elements that surround other elements. the button functions creates a button (no surprise). This is within the monad widget, interaction between components is handled trough that monad.&lt;/p&gt;
&lt;p&gt;On the next line we use the intButton immediately. If we look at the getUsers type signature we see that it requires an &lt;code&gt;Event t ()&lt;/code&gt; argument, this is satisfied by the button. In other words &lt;code&gt;getUsers&lt;/code&gt; will triggered on the button event. The result is once more put in the monadwidget. Finally we map the result to assume success or Nothing, it will be just a list of users now. The holdDyn function is then used to give a default value to the resulting event in case of nothing, we always display either the default or the request result.&lt;/p&gt;
&lt;h2 id=&quot;markup-with-reflex&quot;&gt;Markup with reflex&lt;/h2&gt;
&lt;p&gt;For the &lt;code&gt;postMessage&lt;/code&gt; function I made a form with text inputs:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;#cb8-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;		&lt;span class=&quot;co&quot;&gt;-- Post a usermessage and display results&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;#cb8-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;		input &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; messageInput &lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;#cb8-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;		sendMsg &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; button &lt;span class=&quot;st&quot;&gt;&amp;quot;Send Message&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-4&quot;&gt;&lt;a href=&quot;#cb8-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;		messages &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; fmapMaybe reqSuccess &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; postMessage (&lt;span class=&quot;dt&quot;&gt;Right&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; input) sendMsg &lt;/span&gt;
&lt;span id=&quot;cb8-5&quot;&gt;&lt;a href=&quot;#cb8-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;		resulting &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; holdDyn&lt;/span&gt;
&lt;span id=&quot;cb8-6&quot;&gt;&lt;a href=&quot;#cb8-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;			([&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;none&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;none&amp;quot;&lt;/span&gt;) &lt;span class=&quot;st&quot;&gt;&amp;quot;ddd&amp;quot;&lt;/span&gt;]) &lt;span class=&quot;co&quot;&gt;-- what to show if nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-7&quot;&gt;&lt;a href=&quot;#cb8-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;			messages &lt;span class=&quot;co&quot;&gt;-- source of messages (if any)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-8&quot;&gt;&lt;a href=&quot;#cb8-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        _ &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; el &lt;span class=&quot;st&quot;&gt;&amp;quot;div&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-9&quot;&gt;&lt;a href=&quot;#cb8-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            simpleList resulting fancyMsg &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;messageInput&lt;/code&gt; is a function that returns a “dynamic message” (see below), the button is for sending of messages. To display we use a similar pattern however this time we’ll mark it up in HTML with fancy messages. We traverse over the dynamic list with the &lt;code&gt;simpleList&lt;/code&gt; function, here I expected traverse to work.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;#cb9-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;#cb9-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;    fancyMsg ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Element&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EventResult&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;GhcjsDomSpace&lt;/span&gt; t)&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;#cb9-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    fancyMsg msg &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; elClass &lt;span class=&quot;st&quot;&gt;&amp;quot;div&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-4&quot;&gt;&lt;a href=&quot;#cb9-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        _ &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; elDynHtml&amp;#39; &lt;span class=&quot;st&quot;&gt;&amp;quot;h1&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; Text.pack &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; name &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; from &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; msg&lt;/span&gt;
&lt;span id=&quot;cb9-5&quot;&gt;&lt;a href=&quot;#cb9-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        elDynHtml&amp;#39; &lt;span class=&quot;st&quot;&gt;&amp;quot;span&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; Text.pack &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; content &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; msg&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Every message is put in a &lt;code&gt;div&lt;/code&gt; element, for displaying dynamic content however we need to use &lt;code&gt;elDynhtml&apos;&lt;/code&gt; function, there is no way of getting a value out of dynamic, we can only show it to the user. This is a strong safety guarantee.&lt;/p&gt;
&lt;h2 id=&quot;reflex-react-component&quot;&gt;Reflex “react component”&lt;/h2&gt;
&lt;p&gt;Input fields can be combined together into larger components, which is showcased in the Message form:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;#cb10-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;messageInput ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;#cb10-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;messageInput &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;#cb10-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    user &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; userInput&lt;/span&gt;
&lt;span id=&quot;cb10-4&quot;&gt;&lt;a href=&quot;#cb10-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    message &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; labeledInput &lt;span class=&quot;st&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-5&quot;&gt;&lt;a href=&quot;#cb10-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; user) &lt;span class=&quot;op&quot;&gt;&amp;lt;*&amp;gt;&lt;/span&gt; (Text.unpack &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; _textInput_value message)&lt;/span&gt;
&lt;span id=&quot;cb10-6&quot;&gt;&lt;a href=&quot;#cb10-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-7&quot;&gt;&lt;a href=&quot;#cb10-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;userInput ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb10-8&quot;&gt;&lt;a href=&quot;#cb10-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;userInput &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-9&quot;&gt;&lt;a href=&quot;#cb10-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        username &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; labeledInput &lt;span class=&quot;st&quot;&gt;&amp;quot;username&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-10&quot;&gt;&lt;a href=&quot;#cb10-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        emailInput &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; labeledInput &lt;span class=&quot;st&quot;&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-11&quot;&gt;&lt;a href=&quot;#cb10-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; Text.unpack &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; _textInput_value username &lt;span class=&quot;op&quot;&gt;&amp;lt;*&amp;gt;&lt;/span&gt; (Text.unpack &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; _textInput_value emailInput)&lt;/span&gt;
&lt;span id=&quot;cb10-12&quot;&gt;&lt;a href=&quot;#cb10-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-13&quot;&gt;&lt;a href=&quot;#cb10-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;labeledInput ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text.Text&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;TextInput&lt;/span&gt; t)&lt;/span&gt;
&lt;span id=&quot;cb10-14&quot;&gt;&lt;a href=&quot;#cb10-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;labeledInput label &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; elClass &lt;span class=&quot;st&quot;&gt;&amp;quot;div&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;field&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-15&quot;&gt;&lt;a href=&quot;#cb10-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    elClass &lt;span class=&quot;st&quot;&gt;&amp;quot;label&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;label&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; text label&lt;/span&gt;
&lt;span id=&quot;cb10-16&quot;&gt;&lt;a href=&quot;#cb10-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    elClass &lt;span class=&quot;st&quot;&gt;&amp;quot;div&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;control&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; textInput (def &lt;span class=&quot;op&quot;&gt;&amp;amp;&lt;/span&gt; textInputConfig_attributes &lt;span class=&quot;op&quot;&gt;.~&lt;/span&gt; constDyn (Text.pack &lt;span class=&quot;st&quot;&gt;&amp;quot;class&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=:&lt;/span&gt; Text.pack &lt;span class=&quot;st&quot;&gt;&amp;quot;input&amp;quot;&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is done with applicative fmap &lt;code&gt;&amp;lt;$&amp;gt;&lt;/code&gt; and spaceship &lt;code&gt;&amp;lt;*&amp;gt;&lt;/code&gt;. That last line sets some extra confiugrations can be set withLenses for textInput, which is another &lt;a href=&quot;http://hackage.haskell.org/package/lens&quot;&gt;rabithole&lt;/a&gt;. They can simply be thought of as getters and setters for haskell, although more powerfull.&lt;/p&gt;
&lt;p&gt;Note that these functions are analogue to a react component, and see the difference! They compose perfectly and will function independently.&lt;/p&gt;
&lt;p&gt;Feel the power.&lt;/p&gt;
&lt;p&gt;My only complaint is that the resulting JavaScript binary is huge, 8MB, 2MB after using the &lt;a href=&quot;https://github.com/ghcjs/ghcjs/wiki/Deployment&quot;&gt;closure compiler&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;I’m very pleased with reflex, now I don’t have to deal with JavaScript, I can prototype my API rapidly and I’m not restricted to an architecture. It is better than I expected, the core seems really well designed. The only downside is the large binary. None the less I’m willing to use this for a larger project.&lt;/p&gt;
&lt;h1 id=&quot;links&quot;&gt;Links&lt;/h1&gt;
&lt;p&gt;For convenience here is a list of used resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jappeace/awesome-project-name/tree/reflex&quot;&gt;Complete sources for this post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/reflex-frp/reflex&quot;&gt;Reflex&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/reflex-frp/reflex-platform/blob/develop/docs/project-development.md&quot;&gt;Reflex project development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/meditans/haskell-webapps/tree/master/UI/ReflexFRP/mockLoginPage&quot;&gt;Example frp app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://hackage.haskell.org/package/servant-reflex-0.3.3/candidate&quot;&gt;Servant reflex release candidate docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://docs.reflex-frp.org/en/latest/&quot;&gt;Explenation of things&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;sources&quot;&gt;Sources&lt;/h1&gt;
&lt;p&gt;The project has become too big to share all files, as always there is the &lt;a href=&quot;https://github.com/jappeace/awesome-project-name/tree/reflex&quot;&gt;github link&lt;/a&gt;. I will however put all discussed code in complete form in here.&lt;/p&gt;
&lt;h2 id=&quot;backendsrclib.hs&quot;&gt;backend/src/Lib.hs&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb11&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb11-1&quot;&gt;&lt;a href=&quot;#cb11-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE DataKinds #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-2&quot;&gt;&lt;a href=&quot;#cb11-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE TypeOperators #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-3&quot;&gt;&lt;a href=&quot;#cb11-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-4&quot;&gt;&lt;a href=&quot;#cb11-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# OPTIONS_GHC -Wno-missing-monadfail-instances #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-5&quot;&gt;&lt;a href=&quot;#cb11-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-6&quot;&gt;&lt;a href=&quot;#cb11-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-7&quot;&gt;&lt;a href=&quot;#cb11-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lib&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-8&quot;&gt;&lt;a href=&quot;#cb11-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( webAppEntry&lt;/span&gt;
&lt;span id=&quot;cb11-9&quot;&gt;&lt;a href=&quot;#cb11-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-10&quot;&gt;&lt;a href=&quot;#cb11-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-11&quot;&gt;&lt;a href=&quot;#cb11-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Servant&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-12&quot;&gt;&lt;a href=&quot;#cb11-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Common&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-13&quot;&gt;&lt;a href=&quot;#cb11-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Control.Monad.IO.Class&lt;/span&gt;(liftIO)&lt;/span&gt;
&lt;span id=&quot;cb11-14&quot;&gt;&lt;a href=&quot;#cb11-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Network.Wai&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;Application&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb11-15&quot;&gt;&lt;a href=&quot;#cb11-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Network.Wai.Handler.Warp&lt;/span&gt;(run)&lt;/span&gt;
&lt;span id=&quot;cb11-16&quot;&gt;&lt;a href=&quot;#cb11-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt;           &lt;span class=&quot;dt&quot;&gt;Database.PostgreSQL.Simple&lt;/span&gt;   (&lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb11-17&quot;&gt;&lt;a href=&quot;#cb11-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DB&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DB&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-18&quot;&gt;&lt;a href=&quot;#cb11-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt;           &lt;span class=&quot;dt&quot;&gt;Database.Beam.Backend.SQL.BeamExtensions&lt;/span&gt; (runInsertReturningList)&lt;/span&gt;
&lt;span id=&quot;cb11-19&quot;&gt;&lt;a href=&quot;#cb11-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-20&quot;&gt;&lt;a href=&quot;#cb11-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Database.Beam&lt;/span&gt;                            &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Beam&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-21&quot;&gt;&lt;a href=&quot;#cb11-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Database.Beam.Postgres&lt;/span&gt;                            &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgBeam&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-22&quot;&gt;&lt;a href=&quot;#cb11-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Text&lt;/span&gt;(pack, unpack)&lt;/span&gt;
&lt;span id=&quot;cb11-23&quot;&gt;&lt;a href=&quot;#cb11-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-24&quot;&gt;&lt;a href=&quot;#cb11-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Webservice&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ServiceAPI&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb11-25&quot;&gt;&lt;a href=&quot;#cb11-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Raw&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- JS entry point&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-26&quot;&gt;&lt;a href=&quot;#cb11-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-27&quot;&gt;&lt;a href=&quot;#cb11-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;webservice ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Webservice&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-28&quot;&gt;&lt;a href=&quot;#cb11-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;webservice &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-29&quot;&gt;&lt;a href=&quot;#cb11-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-30&quot;&gt;&lt;a href=&quot;#cb11-30&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;users ::&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb11-31&quot;&gt;&lt;a href=&quot;#cb11-31&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;users &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-32&quot;&gt;&lt;a href=&quot;#cb11-32&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  [ &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Isaac Newton&amp;quot;&lt;/span&gt;    &lt;span class=&quot;st&quot;&gt;&amp;quot;isaac@newton.co.uk&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-33&quot;&gt;&lt;a href=&quot;#cb11-33&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  , &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Albert Einstein&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;ae@mc2.org&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-34&quot;&gt;&lt;a href=&quot;#cb11-34&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ]&lt;/span&gt;
&lt;span id=&quot;cb11-35&quot;&gt;&lt;a href=&quot;#cb11-35&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-36&quot;&gt;&lt;a href=&quot;#cb11-36&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;messages ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Handler&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb11-37&quot;&gt;&lt;a href=&quot;#cb11-37&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;messages conn message &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb11-38&quot;&gt;&lt;a href=&quot;#cb11-38&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  fromDb &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; liftIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb11-39&quot;&gt;&lt;a href=&quot;#cb11-39&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    PgBeam.runBeamPostgres conn &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-40&quot;&gt;&lt;a href=&quot;#cb11-40&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; user &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; from message&lt;/span&gt;
&lt;span id=&quot;cb11-41&quot;&gt;&lt;a href=&quot;#cb11-41&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      [foundUser] &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runInsertReturningList (DB._ausers DB.awesomeDB) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb11-42&quot;&gt;&lt;a href=&quot;#cb11-42&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          Beam.insertExpressions [&lt;span class=&quot;dt&quot;&gt;DB.User&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb11-43&quot;&gt;&lt;a href=&quot;#cb11-43&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            Beam.default_&lt;/span&gt;
&lt;span id=&quot;cb11-44&quot;&gt;&lt;a href=&quot;#cb11-44&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            (Beam.val_ (&lt;span class=&quot;fu&quot;&gt;pack&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; name &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; user ))&lt;/span&gt;
&lt;span id=&quot;cb11-45&quot;&gt;&lt;a href=&quot;#cb11-45&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            (Beam.val_ (&lt;span class=&quot;fu&quot;&gt;pack&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; email &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; user ))&lt;/span&gt;
&lt;span id=&quot;cb11-46&quot;&gt;&lt;a href=&quot;#cb11-46&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id=&quot;cb11-47&quot;&gt;&lt;a href=&quot;#cb11-47&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      _ &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runInsertReturningList (DB._messages DB.awesomeDB) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb11-48&quot;&gt;&lt;a href=&quot;#cb11-48&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          Beam.insertExpressions &lt;/span&gt;
&lt;span id=&quot;cb11-49&quot;&gt;&lt;a href=&quot;#cb11-49&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            [&lt;span class=&quot;dt&quot;&gt;DB.Message&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb11-50&quot;&gt;&lt;a href=&quot;#cb11-50&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;              Beam.default_ &lt;/span&gt;
&lt;span id=&quot;cb11-51&quot;&gt;&lt;a href=&quot;#cb11-51&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;              (Beam.val_ (Beam.pk foundUser))&lt;/span&gt;
&lt;span id=&quot;cb11-52&quot;&gt;&lt;a href=&quot;#cb11-52&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;              (Beam.val_ (&lt;span class=&quot;fu&quot;&gt;pack&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; content message))&lt;/span&gt;
&lt;span id=&quot;cb11-53&quot;&gt;&lt;a href=&quot;#cb11-53&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            ]&lt;/span&gt;
&lt;span id=&quot;cb11-54&quot;&gt;&lt;a href=&quot;#cb11-54&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      Beam.runSelectReturningList &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; Beam.select &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb11-55&quot;&gt;&lt;a href=&quot;#cb11-55&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        usr &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; (Beam.all_ (DB._ausers DB.awesomeDB))&lt;/span&gt;
&lt;span id=&quot;cb11-56&quot;&gt;&lt;a href=&quot;#cb11-56&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        msg &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; Beam.oneToMany_ (DB._messages DB.awesomeDB) DB._from usr&lt;/span&gt;
&lt;span id=&quot;cb11-57&quot;&gt;&lt;a href=&quot;#cb11-57&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (msg, usr)&lt;/span&gt;
&lt;span id=&quot;cb11-58&quot;&gt;&lt;a href=&quot;#cb11-58&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-59&quot;&gt;&lt;a href=&quot;#cb11-59&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (&lt;/span&gt;
&lt;span id=&quot;cb11-60&quot;&gt;&lt;a href=&quot;#cb11-60&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      \(msg, usr) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-61&quot;&gt;&lt;a href=&quot;#cb11-61&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        (&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-62&quot;&gt;&lt;a href=&quot;#cb11-62&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          (unpack &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; DB._name usr)&lt;/span&gt;
&lt;span id=&quot;cb11-63&quot;&gt;&lt;a href=&quot;#cb11-63&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          (unpack &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; DB._email usr))&lt;/span&gt;
&lt;span id=&quot;cb11-64&quot;&gt;&lt;a href=&quot;#cb11-64&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        (unpack &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; DB._content msg)&lt;/span&gt;
&lt;span id=&quot;cb11-65&quot;&gt;&lt;a href=&quot;#cb11-65&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ) fromDb&lt;/span&gt;
&lt;span id=&quot;cb11-66&quot;&gt;&lt;a href=&quot;#cb11-66&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-67&quot;&gt;&lt;a href=&quot;#cb11-67&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-68&quot;&gt;&lt;a href=&quot;#cb11-68&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;server ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Webservice&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-69&quot;&gt;&lt;a href=&quot;#cb11-69&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;server conn&lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-70&quot;&gt;&lt;a href=&quot;#cb11-70&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (&lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; users &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; messages conn) &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; serveDirectoryFileServer &lt;span class=&quot;st&quot;&gt;&amp;quot;dist-ghcjs/build/x86_64-linux/ghcjs-0.2.1/frontend-0.1.0.0/c/webservice/build/webservice/webservice.jsexe/&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-71&quot;&gt;&lt;a href=&quot;#cb11-71&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-72&quot;&gt;&lt;a href=&quot;#cb11-72&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;app ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Application&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-73&quot;&gt;&lt;a href=&quot;#cb11-73&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;app conn &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; serve webservice (server conn)&lt;/span&gt;
&lt;span id=&quot;cb11-74&quot;&gt;&lt;a href=&quot;#cb11-74&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-75&quot;&gt;&lt;a href=&quot;#cb11-75&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;webAppEntry ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb11-76&quot;&gt;&lt;a href=&quot;#cb11-76&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;webAppEntry conn &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; run &lt;span class=&quot;dv&quot;&gt;6868&lt;/span&gt; (app conn)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;commonsrccommon.hs&quot;&gt;common/src/Common.hs&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;#cb12-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE DataKinds #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-2&quot;&gt;&lt;a href=&quot;#cb12-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE TypeOperators #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-3&quot;&gt;&lt;a href=&quot;#cb12-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE DeriveGeneric #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-4&quot;&gt;&lt;a href=&quot;#cb12-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-5&quot;&gt;&lt;a href=&quot;#cb12-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Common&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-6&quot;&gt;&lt;a href=&quot;#cb12-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-7&quot;&gt;&lt;a href=&quot;#cb12-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;GHC.Generics&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb12-8&quot;&gt;&lt;a href=&quot;#cb12-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Servant.API&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-9&quot;&gt;&lt;a href=&quot;#cb12-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Proxy&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-10&quot;&gt;&lt;a href=&quot;#cb12-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Aeson&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;FromJSON&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb12-11&quot;&gt;&lt;a href=&quot;#cb12-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-12&quot;&gt;&lt;a href=&quot;#cb12-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ServiceAPI&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;api&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;users&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Get&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] [&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb12-13&quot;&gt;&lt;a href=&quot;#cb12-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;api&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ReqBody&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Post&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] [&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb12-14&quot;&gt;&lt;a href=&quot;#cb12-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-15&quot;&gt;&lt;a href=&quot;#cb12-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; {&lt;/span&gt;
&lt;span id=&quot;cb12-16&quot;&gt;&lt;a href=&quot;#cb12-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  from ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb12-17&quot;&gt;&lt;a href=&quot;#cb12-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  content ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-18&quot;&gt;&lt;a href=&quot;#cb12-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;} &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb12-19&quot;&gt;&lt;a href=&quot;#cb12-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-20&quot;&gt;&lt;a href=&quot;#cb12-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-21&quot;&gt;&lt;a href=&quot;#cb12-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-22&quot;&gt;&lt;a href=&quot;#cb12-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-23&quot;&gt;&lt;a href=&quot;#cb12-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-24&quot;&gt;&lt;a href=&quot;#cb12-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; name ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-25&quot;&gt;&lt;a href=&quot;#cb12-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; email ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-26&quot;&gt;&lt;a href=&quot;#cb12-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  } &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb12-27&quot;&gt;&lt;a href=&quot;#cb12-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-28&quot;&gt;&lt;a href=&quot;#cb12-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-29&quot;&gt;&lt;a href=&quot;#cb12-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-30&quot;&gt;&lt;a href=&quot;#cb12-30&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-31&quot;&gt;&lt;a href=&quot;#cb12-31&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;serviceAPI ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ServiceAPI&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-32&quot;&gt;&lt;a href=&quot;#cb12-32&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;serviceAPI &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;frontendsrclib.hs&quot;&gt;frontend/src/Lib.hs&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb13&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb13-1&quot;&gt;&lt;a href=&quot;#cb13-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE OverloadedStrings #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-2&quot;&gt;&lt;a href=&quot;#cb13-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# OPTIONS_GHC -fprint-explicit-kinds -Wpartial-type-signatures #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-3&quot;&gt;&lt;a href=&quot;#cb13-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-4&quot;&gt;&lt;a href=&quot;#cb13-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-5&quot;&gt;&lt;a href=&quot;#cb13-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lib&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-6&quot;&gt;&lt;a href=&quot;#cb13-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ( reflex&lt;/span&gt;
&lt;span id=&quot;cb13-7&quot;&gt;&lt;a href=&quot;#cb13-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-8&quot;&gt;&lt;a href=&quot;#cb13-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Reflex&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-9&quot;&gt;&lt;a href=&quot;#cb13-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Reflex.Dom&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-10&quot;&gt;&lt;a href=&quot;#cb13-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Text&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-11&quot;&gt;&lt;a href=&quot;#cb13-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Control.Applicative&lt;/span&gt; ((&amp;lt;*&amp;gt;), (&amp;lt;$&amp;gt;))&lt;/span&gt;
&lt;span id=&quot;cb13-12&quot;&gt;&lt;a href=&quot;#cb13-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Common&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-13&quot;&gt;&lt;a href=&quot;#cb13-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Servant.Reflex&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-14&quot;&gt;&lt;a href=&quot;#cb13-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ServantClient&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-15&quot;&gt;&lt;a href=&quot;#cb13-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-16&quot;&gt;&lt;a href=&quot;#cb13-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;reflex ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt;()&lt;/span&gt;
&lt;span id=&quot;cb13-17&quot;&gt;&lt;a href=&quot;#cb13-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;reflex &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-18&quot;&gt;&lt;a href=&quot;#cb13-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  mainWidget &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-19&quot;&gt;&lt;a href=&quot;#cb13-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    el &lt;span class=&quot;st&quot;&gt;&amp;quot;div&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-20&quot;&gt;&lt;a href=&quot;#cb13-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;co&quot;&gt;-- babys steps, get users from memory&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-21&quot;&gt;&lt;a href=&quot;#cb13-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        intButton  &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; button &lt;span class=&quot;st&quot;&gt;&amp;quot;Get Users&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-22&quot;&gt;&lt;a href=&quot;#cb13-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        serverInts &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; fmapMaybe reqSuccess &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; getUsers intButton&lt;/span&gt;
&lt;span id=&quot;cb13-23&quot;&gt;&lt;a href=&quot;#cb13-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        display &lt;span class=&quot;op&quot;&gt;=&amp;lt;&amp;lt;&lt;/span&gt; holdDyn ([&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;none&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;none&amp;quot;&lt;/span&gt;]) serverInts&lt;/span&gt;
&lt;span id=&quot;cb13-24&quot;&gt;&lt;a href=&quot;#cb13-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-25&quot;&gt;&lt;a href=&quot;#cb13-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;co&quot;&gt;-- Post a usermessage and display results&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-26&quot;&gt;&lt;a href=&quot;#cb13-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        input &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; messageInput &lt;/span&gt;
&lt;span id=&quot;cb13-27&quot;&gt;&lt;a href=&quot;#cb13-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        sendMsg &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; button &lt;span class=&quot;st&quot;&gt;&amp;quot;Send Message&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-28&quot;&gt;&lt;a href=&quot;#cb13-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        messages &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; fmapMaybe reqSuccess &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; postMessage (&lt;span class=&quot;dt&quot;&gt;Right&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; input) sendMsg &lt;/span&gt;
&lt;span id=&quot;cb13-29&quot;&gt;&lt;a href=&quot;#cb13-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        resulting &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; holdDyn&lt;/span&gt;
&lt;span id=&quot;cb13-30&quot;&gt;&lt;a href=&quot;#cb13-30&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            ([&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;none&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;none&amp;quot;&lt;/span&gt;) &lt;span class=&quot;st&quot;&gt;&amp;quot;ddd&amp;quot;&lt;/span&gt;]) &lt;span class=&quot;co&quot;&gt;-- what to show if nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-31&quot;&gt;&lt;a href=&quot;#cb13-31&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            messages &lt;span class=&quot;co&quot;&gt;-- source of messages (if any)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-32&quot;&gt;&lt;a href=&quot;#cb13-32&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-33&quot;&gt;&lt;a href=&quot;#cb13-33&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        _ &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; el &lt;span class=&quot;st&quot;&gt;&amp;quot;div&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-34&quot;&gt;&lt;a href=&quot;#cb13-34&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            simpleList resulting fancyMsg &lt;/span&gt;
&lt;span id=&quot;cb13-35&quot;&gt;&lt;a href=&quot;#cb13-35&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb13-36&quot;&gt;&lt;a href=&quot;#cb13-36&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-37&quot;&gt;&lt;a href=&quot;#cb13-37&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;    fancyMsg ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Element&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EventResult&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;GhcjsDomSpace&lt;/span&gt; t)&lt;/span&gt;
&lt;span id=&quot;cb13-38&quot;&gt;&lt;a href=&quot;#cb13-38&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    fancyMsg msg &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; elClass &lt;span class=&quot;st&quot;&gt;&amp;quot;div&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-39&quot;&gt;&lt;a href=&quot;#cb13-39&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        _ &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; elDynHtml&amp;#39; &lt;span class=&quot;st&quot;&gt;&amp;quot;h1&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; Text.pack &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; name &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; from &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; msg&lt;/span&gt;
&lt;span id=&quot;cb13-40&quot;&gt;&lt;a href=&quot;#cb13-40&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        elDynHtml&amp;#39; &lt;span class=&quot;st&quot;&gt;&amp;quot;span&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; Text.pack &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; content &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; msg&lt;/span&gt;
&lt;span id=&quot;cb13-41&quot;&gt;&lt;a href=&quot;#cb13-41&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-42&quot;&gt;&lt;a href=&quot;#cb13-42&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;messageInput ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb13-43&quot;&gt;&lt;a href=&quot;#cb13-43&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;messageInput &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-44&quot;&gt;&lt;a href=&quot;#cb13-44&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    user &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; userInput&lt;/span&gt;
&lt;span id=&quot;cb13-45&quot;&gt;&lt;a href=&quot;#cb13-45&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    message &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; labeledInput &lt;span class=&quot;st&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-46&quot;&gt;&lt;a href=&quot;#cb13-46&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; user) &lt;span class=&quot;op&quot;&gt;&amp;lt;*&amp;gt;&lt;/span&gt; (Text.unpack &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; _textInput_value message)&lt;/span&gt;
&lt;span id=&quot;cb13-47&quot;&gt;&lt;a href=&quot;#cb13-47&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-48&quot;&gt;&lt;a href=&quot;#cb13-48&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;userInput ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb13-49&quot;&gt;&lt;a href=&quot;#cb13-49&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;userInput &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-50&quot;&gt;&lt;a href=&quot;#cb13-50&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        username &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; labeledInput &lt;span class=&quot;st&quot;&gt;&amp;quot;username&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-51&quot;&gt;&lt;a href=&quot;#cb13-51&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        emailInput &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; labeledInput &lt;span class=&quot;st&quot;&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-52&quot;&gt;&lt;a href=&quot;#cb13-52&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; Text.unpack &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; _textInput_value username &lt;span class=&quot;op&quot;&gt;&amp;lt;*&amp;gt;&lt;/span&gt; (Text.unpack &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; _textInput_value emailInput)&lt;/span&gt;
&lt;span id=&quot;cb13-53&quot;&gt;&lt;a href=&quot;#cb13-53&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-54&quot;&gt;&lt;a href=&quot;#cb13-54&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;labeledInput ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text.Text&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;TextInput&lt;/span&gt; t)&lt;/span&gt;
&lt;span id=&quot;cb13-55&quot;&gt;&lt;a href=&quot;#cb13-55&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;labeledInput label &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; elClass &lt;span class=&quot;st&quot;&gt;&amp;quot;div&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;field&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-56&quot;&gt;&lt;a href=&quot;#cb13-56&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    elClass &lt;span class=&quot;st&quot;&gt;&amp;quot;label&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;label&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; text label&lt;/span&gt;
&lt;span id=&quot;cb13-57&quot;&gt;&lt;a href=&quot;#cb13-57&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    elClass &lt;span class=&quot;st&quot;&gt;&amp;quot;div&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;control&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; textInput (def &lt;span class=&quot;op&quot;&gt;&amp;amp;&lt;/span&gt; textInputConfig_attributes &lt;span class=&quot;op&quot;&gt;.~&lt;/span&gt; constDyn (Text.pack &lt;span class=&quot;st&quot;&gt;&amp;quot;class&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=:&lt;/span&gt; Text.pack &lt;span class=&quot;st&quot;&gt;&amp;quot;input&amp;quot;&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;frontendsrcservantclient.hs&quot;&gt;frontend/src/ServantClient.hs&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb14-1&quot;&gt;&lt;a href=&quot;#cb14-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE OverloadedStrings #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-2&quot;&gt;&lt;a href=&quot;#cb14-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE RankNTypes #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-3&quot;&gt;&lt;a href=&quot;#cb14-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE TypeApplications #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-4&quot;&gt;&lt;a href=&quot;#cb14-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# OPTIONS_GHC -Wno-partial-type-signatures #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-5&quot;&gt;&lt;a href=&quot;#cb14-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-6&quot;&gt;&lt;a href=&quot;#cb14-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE NoMonomorphismRestriction          #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-7&quot;&gt;&lt;a href=&quot;#cb14-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE PartialTypeSignatures #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-8&quot;&gt;&lt;a href=&quot;#cb14-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE ScopedTypeVariables #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-9&quot;&gt;&lt;a href=&quot;#cb14-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE  TypeApplications #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-10&quot;&gt;&lt;a href=&quot;#cb14-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE TypeOperators #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-11&quot;&gt;&lt;a href=&quot;#cb14-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-12&quot;&gt;&lt;a href=&quot;#cb14-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- | This modules purpose is just to generate the xhr clients.&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-13&quot;&gt;&lt;a href=&quot;#cb14-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;--   there is some type magick going on generating these,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-14&quot;&gt;&lt;a href=&quot;#cb14-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;--   therefore the functions are isolated.&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-15&quot;&gt;&lt;a href=&quot;#cb14-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ServantClient&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-16&quot;&gt;&lt;a href=&quot;#cb14-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ( postMessage, getUsers &lt;/span&gt;
&lt;span id=&quot;cb14-17&quot;&gt;&lt;a href=&quot;#cb14-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-18&quot;&gt;&lt;a href=&quot;#cb14-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-19&quot;&gt;&lt;a href=&quot;#cb14-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Reflex&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-20&quot;&gt;&lt;a href=&quot;#cb14-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Reflex.Dom&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-21&quot;&gt;&lt;a href=&quot;#cb14-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Text&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-22&quot;&gt;&lt;a href=&quot;#cb14-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Servant.API&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-23&quot;&gt;&lt;a href=&quot;#cb14-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Common&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-24&quot;&gt;&lt;a href=&quot;#cb14-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Servant.Reflex&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-25&quot;&gt;&lt;a href=&quot;#cb14-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Proxy&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-26&quot;&gt;&lt;a href=&quot;#cb14-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-27&quot;&gt;&lt;a href=&quot;#cb14-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- | This intermediate definition is necisarry because the @m is similar for both clients,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-28&quot;&gt;&lt;a href=&quot;#cb14-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;--   they have the same wrapping monad however the containing type is different&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-29&quot;&gt;&lt;a href=&quot;#cb14-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;--   (which is why we have the nomonomorphism restirction disabled)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-30&quot;&gt;&lt;a href=&quot;#cb14-30&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;apiClients ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; t m&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; _&lt;/span&gt;
&lt;span id=&quot;cb14-31&quot;&gt;&lt;a href=&quot;#cb14-31&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;apiClients &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; client serviceAPI (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;m) (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;()) (constDyn url)&lt;/span&gt;
&lt;span id=&quot;cb14-32&quot;&gt;&lt;a href=&quot;#cb14-32&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; url ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;BaseUrl&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-33&quot;&gt;&lt;a href=&quot;#cb14-33&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        url &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;BasePath&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-34&quot;&gt;&lt;a href=&quot;#cb14-34&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-35&quot;&gt;&lt;a href=&quot;#cb14-35&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;getUsers ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m&lt;/span&gt;
&lt;span id=&quot;cb14-36&quot;&gt;&lt;a href=&quot;#cb14-36&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t ()  &lt;span class=&quot;co&quot;&gt;-- ^ Trigger the XHR Request&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-37&quot;&gt;&lt;a href=&quot;#cb14-37&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;ReqResult&lt;/span&gt; () [&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;])) &lt;span class=&quot;co&quot;&gt;-- ^ Consume the answer&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-38&quot;&gt;&lt;a href=&quot;#cb14-38&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;postMessage ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadWidget&lt;/span&gt; t m&lt;/span&gt;
&lt;span id=&quot;cb14-39&quot;&gt;&lt;a href=&quot;#cb14-39&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text.Text&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb14-40&quot;&gt;&lt;a href=&quot;#cb14-40&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t ()&lt;/span&gt;
&lt;span id=&quot;cb14-41&quot;&gt;&lt;a href=&quot;#cb14-41&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Event&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;ReqResult&lt;/span&gt; () [&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;]))&lt;/span&gt;
&lt;span id=&quot;cb14-42&quot;&gt;&lt;a href=&quot;#cb14-42&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(getUsers &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; postMessage) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; apiClients&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Back to the Netherlands!</title>
    <link href="https://jappieklooster.nl/back-to-the-netherlands.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2018-09-23:/back-to-the-netherlands.html</id>
    <published>2018-09-23T18:21:00Z</published>
    <updated>2018-09-23T18:21:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="story"/>
    <summary type="html">&lt;p&gt;After a year in foreign countries, I’ve returned home. Last week my working holiday visa expired, and unlike a friend of mine, I did not want to be deported in handcuffs.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2018/dutch-flag.svg&quot; alt=&quot;Dutch flag&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Dutch flag&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I quite enjoyed my stay in Australia, the people are relax, life is good. I’ve drank lots&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;After a year in foreign countries, I’ve returned home. Last week my working holiday visa expired, and unlike a friend of mine, I did not want to be deported in handcuffs.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2018/dutch-flag.svg&quot; alt=&quot;Dutch flag&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Dutch flag&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I quite enjoyed my stay in Australia, the people are relax, life is good. I’ve drank lots of coffee and ate many a Kangaroo, but it’s good to be back and speak my own language. The people just “&lt;a href=&quot;https://stuffdutchpeoplelike.com/2010/11/26/no-56-normalcy-doe-normaal/&quot;&gt;act normal&lt;/a&gt;”,&lt;/p&gt;
&lt;p&gt;First I was a month in Indonesia, essentially looking for jobs in Australia (as you do), and hanging out with my then girlfriend. Then in Sydney I quickly found a job and place to live. Three interviews were pre-arranged, they all got converted into offers. The first one was &lt;a href=&quot;https://stackchat.com/#contact-area&quot;&gt;stackchat&lt;/a&gt;, they gave me a pretty bad offer, I needed money most yet they came with equity. Then there was &lt;a href=&quot;https://www.ayudasystems.com/&quot;&gt;ayuda&lt;/a&gt;, I probably could’ve asked them lots more money as they were hardly strapped for cash. &lt;a href=&quot;https://www.openlearning.com/&quot;&gt;Openlearning&lt;/a&gt; offered most though, more then I asked for, which was nice. I took the highest.&lt;/p&gt;
&lt;p&gt;Around new year the relationship with Jesiska was in crisis, and I went back to Indonesia, where it failed. Happy new year.&lt;/p&gt;
&lt;p&gt;then, around February the company wanted to initiate sponsorship. However I had become pretty unhappy with the working arrangement. It looked like I was just being kept busy, while having no impact on anything. That working relationship also ended there.&lt;/p&gt;
&lt;p&gt;At that point I seriously considered going back, This was my lowest point in Australia. I had nothing there except a little hobby project started with some friends. ex-Colleagues at Open Learning, I was crestfallen. Although they were being nice about my essentially destroyed life, in Netherlands we would rip on each other at this point, You could at least joke about it you know. I’m too facetious I hear.&lt;/p&gt;
&lt;p&gt;Here I decided that rather than giving up so easily I’d fight for staying in Australia as a software engineer. I just had arranged better housing, now I bet I could also arrange better work! Easier said then done, I emailed so many companies, I even made a little movie to sell myself. Few replies but some did.&lt;/p&gt;
&lt;p&gt;First there was Silicon Valley Chicken, they wanted to sell chicken trough an app with a game. Completely aimed at Gamers, and only order trough the app. I wasn’t too excited about that, they weren’t excited about me being on working holiday visa. After that I met &lt;a href=&quot;https://www.daisee.com/&quot;&gt;Daisee&lt;/a&gt; at the functional programming meetup. I managed to get an interview. Turned out it was a Haskell job. I was super excited about that. Then &lt;a href=&quot;https://www.jointrunk.com/&quot;&gt;Trunk&lt;/a&gt; wanted to deliver version control to designers. But I kind off neglected them in favor of the Haskell opportunity.&lt;/p&gt;
&lt;p&gt;This was role reversal, now the friends had a pretty crappy job compared to doing Haskell. Especially considering the company had taken up &lt;a href=&quot;https://azure.microsoft.com/en-us/services/cosmos-db/&quot;&gt;Cosmos db&lt;/a&gt; which required running windows. They were both open source advocates, requiring to run this made them.. Unhappy.&lt;/p&gt;
&lt;p&gt;But I was happy. For a couple of months. Daisee kept hiring people and we grew. The more time passed the more responsibility I had to give away, until I was focused upon the one project. Which then got canned. Not that it bothered me as I was planning for the next stage in my life.&lt;/p&gt;
&lt;p&gt;Going to the Philippines! Except, everyone I spoke to was pretty negative about it, and the offer from Daisee wasn’t as nice as I expected. Back home I am, not that it’s bad, just sudden. I’ll be staying here for some time, doing remote work for Daisee as a &lt;a href=&quot;http://penguin.engineer/&quot;&gt;company&lt;/a&gt;! Meanwhile Daisee is working on a work visa for Australia. This seems much better than the Philippines, which felt more like a golden prison.&lt;/p&gt;
&lt;p&gt;This is all seems pretty random, oh well, such is life. I had fun at least.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>NixOS on encrypted btrfs</title>
    <link href="https://jappieklooster.nl/nixos-on-encrypted-btrfs.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2018-08-19:/nixos-on-encrypted-btrfs.html</id>
    <published>2018-08-19T13:02:00Z</published>
    <updated>2022-01-30T13:18:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;Nixos is heroin for tinkerers. Paradise can be tinkered together and be freely shared among peers because it’s fully reproducible! Jappie wanted more, he wanted a secure disk &lt;em&gt;and&lt;/em&gt; a BTRFS. There used to be no guides for this, now there is.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2018/locked_btrfs.svg&quot; alt=&quot;Locked btrfs on nixos&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Locked btrfs on nixos&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The bullet was bitten,&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Nixos is heroin for tinkerers. Paradise can be tinkered together and be freely shared among peers because it’s fully reproducible! Jappie wanted more, he wanted a secure disk &lt;em&gt;and&lt;/em&gt; a BTRFS. There used to be no guides for this, now there is.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2018/locked_btrfs.svg&quot; alt=&quot;Locked btrfs on nixos&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Locked btrfs on nixos&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The bullet was bitten, BTRFS was made to work on a LUKS encrypted disk. This isn’t hard, with care and precision. To help a reader we document the journey towards BTRFS. Commands compiled and included.&lt;/p&gt;
&lt;h1 id=&quot;getting-started&quot;&gt;Getting started&lt;/h1&gt;
&lt;p&gt;Get yourself a NixOS &lt;a href=&quot;https://nixos.org/download.html#download-nixos&quot;&gt;live usb&lt;/a&gt;. I use the minimal ISO, because the graphical ISO slows booting and gives no advantage aside from being pretty. Use&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat minimal-nixos.iso &amp;gt; /dev/sdX&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where &lt;code&gt;X&lt;/code&gt; is the usb drive found by &lt;code&gt;lsblk&lt;/code&gt;. &lt;code&gt;X&lt;/code&gt; should be a letter, numbers indicate partitions, which we don’t want to cat upon. Boot into it on the target machine.&lt;/p&gt;
&lt;h1 id=&quot;networking&quot;&gt;Networking&lt;/h1&gt;
&lt;p&gt;Next step is to setup WIFI, you can skip this if you’re on Ethernet:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;wpa_passphrase&lt;/span&gt; SSID PASS &lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; /etc/wpa_supplicant.conf&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;systemctl&lt;/span&gt; restart wpa_supplicant&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first command creates a config for wpa_supplicant. The reader must fill in SSID and PASS of his target wifi network. The second command tells systemd to go restart wpa_supplicant and use the new config.&lt;/p&gt;
&lt;p&gt;Ask google if you’re online: &lt;code&gt;curl google.com&lt;/code&gt; should return a 301 redirect:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode html&quot;&gt;&lt;code class=&quot;sourceCode html&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;HEAD&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; http-equiv&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;content-type&amp;quot;&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; content&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;text/html;charset=utf-8&amp;quot;&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;#cb3-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;TITLE&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;&amp;gt;&lt;/span&gt;301 Moved&lt;span class=&quot;dt&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;TITLE&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;HEAD&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;BODY&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;#cb3-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;H1&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;&amp;gt;&lt;/span&gt;301 Moved&lt;span class=&quot;dt&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;H1&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;#cb3-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;The document has moved&lt;/span&gt;
&lt;span id=&quot;cb3-5&quot;&gt;&lt;a href=&quot;#cb3-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; HREF&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;http://www.google.com/&amp;quot;&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;&amp;gt;&lt;/span&gt;here&lt;span class=&quot;dt&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;&amp;gt;&lt;/span&gt;.&lt;/span&gt;
&lt;span id=&quot;cb3-6&quot;&gt;&lt;a href=&quot;#cb3-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;BODY&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There is no point proceeding until you have networking.&lt;/p&gt;
&lt;h1 id=&quot;partitioning&quot;&gt;Partitioning&lt;/h1&gt;
&lt;p&gt;Now to setup the partitioning on the RIGHT device. Choose carefully. Use &lt;code&gt;lsblk&lt;/code&gt; to figure out which device is RIGHT. You’ll know it’s the WRONG device if you lose data after partitioning. The RIGHT device will be called &lt;code&gt;$dev&lt;/code&gt; hence forward.&lt;/p&gt;
&lt;p&gt;There are no other partitioning tools than gdisk. Only heretics believe there are. Therefore we use gdisk:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;#cb4-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;gdisk&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;$dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;gdisk-cheat-sheet&quot;&gt;Gdisk cheat sheet&lt;/h2&gt;
&lt;table&gt;
&lt;colgroup&gt;
&lt;col style=&quot;width: 11%&quot; /&gt;
&lt;col style=&quot;width: 88%&quot; /&gt;
&lt;/colgroup&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;For printing, to see what’s going on.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;For deletion, you should start out with deleting everything on &lt;code&gt;$dev&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;n&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Is used for creating new partitions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;w&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;is used for writing once finished.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This table just describes the commands needed for the intended partitioning.&lt;/p&gt;
&lt;h2 id=&quot;intended-partitioning&quot;&gt;Intended partitioning&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Number&lt;/th&gt;
&lt;th&gt;type&lt;/th&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;ef00&lt;/td&gt;
&lt;td&gt;+500M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;8200&lt;/td&gt;
&lt;td&gt;+$(SIZE_RAM+ a little)G&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;8300&lt;/td&gt;
&lt;td&gt;(rest of disk)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The first partition will be boot, the second swap[^optional], the third will be everything else. We will encrypt everything else. With type &lt;code&gt;ef00&lt;/code&gt; we will use UEFI for booting. Don’t worry. nix will handle that, mostly. Done. Onwards! [^optional]: This one is optional but allows hibernation. Which is very convenient for laptops. It can also make your system &lt;a href=&quot;https://askubuntu.com/questions/291378/do-we-still-need-swap-partitions-on-servers&quot;&gt;more stable&lt;/a&gt;. Note that Swap files are &lt;a href=&quot;https://wiki.archlinux.org/index.php/Btrfs#Swap_file&quot;&gt;bad&lt;/a&gt; on BTRFS.&lt;/p&gt;
&lt;h1 id=&quot;encryption&quot;&gt;Encryption&lt;/h1&gt;
&lt;p&gt;We use &lt;code&gt;cryptsetup&lt;/code&gt; for encryption. Make sure to select the right partition. We do not want to encrypt the boot partition because then we can’t boot. So if you followed above instructions it will be either &lt;code&gt;3&lt;/code&gt; or &lt;code&gt;p3&lt;/code&gt; (depending on device type). We’ll call it &lt;code&gt;3&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;cryptsetup&lt;/span&gt; luksFormat &lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dev&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;3&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;#cb5-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;cryptsetup&lt;/span&gt; open &lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dev&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;3 nixenc&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first command does the actual formatting, the second one opens up the formatted disk. You’ll need to provide the right password in both cases. Choose one you can remember but is strong. Once decrypted the disk will be mapped to &lt;code&gt;/dev/mapper/nixenc&lt;/code&gt;, note that we supplied that final part in the last command.&lt;/p&gt;
&lt;h1 id=&quot;formatting-filesystems&quot;&gt;Formatting filesystems&lt;/h1&gt;
&lt;p&gt;Partitioning is a distinct step from setting up filesystems.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;#cb6-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;mkfs.vfat&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-n&lt;/span&gt; boot &lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dev&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;1&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;#cb6-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;mkswap&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dev&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;2&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;#cb6-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;swapon&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dev&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;2&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;#cb6-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;mkfs.btrfs&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-L&lt;/span&gt; root /dev/mapper/nixenc&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The boot partition will be &lt;code&gt;vfat&lt;/code&gt; because &lt;a href=&quot;https://wiki.archlinux.org/index.php/EFI_system_partition&quot;&gt;UEFI tells us to&lt;/a&gt;. The everything else partition will be &lt;code&gt;btrfs&lt;/code&gt;, because why are you following this guide if not? Note that we point it at the mapped file, if the &lt;code&gt;&quot;$dev&quot;3&lt;/code&gt;device were to be used directly we’d remove the encryption.&lt;/p&gt;
&lt;h1 id=&quot;moutning-and-subvolumes&quot;&gt;Moutning and subvolumes&lt;/h1&gt;
&lt;p&gt;Wouldn’t it be nice to have subvolumes on your BTRFS? This is not &lt;a href=&quot;https://en.wikipedia.org/wiki/Cargo_cult_programming&quot;&gt;cargo culted&lt;/a&gt; at all.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;#cb7-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;mount&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-t&lt;/span&gt; btrfs /dev/mapper/nixenc /mnt/&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;#cb7-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;btrfs&lt;/span&gt; subvol create /mnt/nixos&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;#cb7-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;umount&lt;/span&gt; /mnt&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;#cb7-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;mount&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-t&lt;/span&gt; btrfs &lt;span class=&quot;at&quot;&gt;-o&lt;/span&gt; subvol=nixos /dev/mapper/nixenc /mnt&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;First we create a nixos subvolume below the root subvolume, eg the nixos operating system will not be installed in the root, but one node below the root, allowing potentially more operating systems to be installed on the same partition. Reverse explaining cargo culting behavior, this maybe a good idea.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;#cb8-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;btrfs&lt;/span&gt; subvol create /mnt/home&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Setting up a subvolume for &lt;code&gt;home&lt;/code&gt; allows btrfs based backups. I used too also make subvolumes for &lt;code&gt;tmp&lt;/code&gt;&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; and &lt;code&gt;var&lt;/code&gt;, but I don’t see the merit in that.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;#cb9-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;mkdir&lt;/span&gt; /mnt/boot&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;#cb9-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;mount&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dev&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;&lt;/span&gt;1 /mnt/boot&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we mount the boot partition. Just to make it detectable by the nix config generation script.&lt;/p&gt;
&lt;h2 id=&quot;did-i-do-everything-right&quot;&gt;Did I do everything right?&lt;/h2&gt;
&lt;p&gt;The second time I ran trough this post everything went quite quickly, so I became skeptical. To verify everything was sane I used the following commands:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;#cb10-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;mount&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;grep&lt;/span&gt; /mnt&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;#cb10-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;ls&lt;/span&gt; /mnt&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first command is to check if the encrypted volume and boot is mounted at the right paths. The second one to verify the folders are created, which are subvolumes. The subvolume command creates a folder so if it exists we presume it worked. But if you’re really unsure you can use &lt;code&gt;btrfs subvol list /mnt/&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&quot;configure-nix&quot;&gt;Configure nix&lt;/h1&gt;
&lt;p&gt;We can use hardware detection to figure out how to setup nix on this setup:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb11&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb11-1&quot;&gt;&lt;a href=&quot;#cb11-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;nixos-generate-config&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;--root&lt;/span&gt; /mnt&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Done.&lt;/p&gt;
&lt;p&gt;Now the user needs to write his own &lt;a href=&quot;https://nixos.org/nixos/manual/index.html#sec-changing-config&quot;&gt;nix config&lt;/a&gt;, or &lt;a href=&quot;https://github.com/jappeace/linux-config/blob/master/configuration.nix&quot;&gt;copy mine&lt;/a&gt; or cherry pick whatever they need (recommend). On a wireless laptop, it’s highly recommended to enable &lt;a href=&quot;https://nixos.wiki/wiki/Wpa_supplicant&quot;&gt;wpa_supplicant&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode nix&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;#cb12-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;networking&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;wireless&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;enable = &lt;span class=&quot;cn&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once configuration is done we can install nix:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb13&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb13-1&quot;&gt;&lt;a href=&quot;#cb13-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;nixos-install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Don’t worry, we can use &lt;code&gt;nixos-rebuild switch&lt;/code&gt; to reconfigure nix whenever once we’re booted into it. Hopefully we boot successfully:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb14-1&quot;&gt;&lt;a href=&quot;#cb14-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;reboot&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Booting is hard, don’t worry if this goes wrong the first &lt;s&gt;10&lt;/s&gt; 30 times.&lt;/p&gt;
&lt;p&gt;You may need to enable UEFI in your BIOS. It’s up to the reader to figure that part out. (press some f keys on boot, f11 maybe?). Alternatively one could setup grub. Good luck with that.&lt;/p&gt;
&lt;p&gt;You can’t read the rest of this post until you’ve booted, go back if you haven’t, you messed up.&lt;/p&gt;
&lt;h1 id=&quot;final-steps&quot;&gt;Final steps&lt;/h1&gt;
&lt;p&gt;Once rebooted you may be stuck at the display manager. Use &lt;code&gt;Alt+f1&lt;/code&gt; to switch to another TTY and login as root, then use &lt;code&gt;passwd your-user-name&lt;/code&gt; to set an initial password. Use &lt;code&gt;Alt+f7&lt;/code&gt; to go back to the display manager.&lt;/p&gt;
&lt;p&gt;I personally haven’t moved all my configuration into nix yet (it’s a big project), but I wrote a &lt;a href=&quot;https://github.com/jappeace/linux-config/blob/master/scripts/nixos-setup.sh&quot;&gt;script&lt;/a&gt; that symlinks all dotfiles, and hardlinks the &lt;code&gt;configuration.nix&lt;/code&gt; to my linux-config project.&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;If you want a subvolume for /tmp, make sure to chmod it to 777 Otherwise various applications get upset. Pulse audio for example doesn’t work well if it can’t write into &lt;code&gt;/tmp&lt;/code&gt;.&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Pragmatic Haskell III: Beam Postgres DB</title>
    <link href="https://jappieklooster.nl/pragmatic-haskell-iii-beam-postgres-db.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2018-08-05:/pragmatic-haskell-iii-beam-postgres-db.html</id>
    <published>2018-08-05T17:30:00Z</published>
    <updated>2023-08-19T12:32:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;Note, I no longer recommend using beam for business as ORM. Please use &lt;a href=&quot;https://www.yesodweb.com/book/persistent&quot;&gt;persistent&lt;/a&gt; instead. Beam is far to complicated for it’s use case. Migrations can be run with &lt;a href=&quot;https://hackage.haskell.org/package/postgresql-migration&quot;&gt;postgresql-migration&lt;/a&gt; for example, using the suggested migrations from persistent. I’d only recommend using beam for hobby projects or as a case&lt;/p&gt;&lt;/blockquote&gt;</summary>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;Note, I no longer recommend using beam for business as ORM. Please use &lt;a href=&quot;https://www.yesodweb.com/book/persistent&quot;&gt;persistent&lt;/a&gt; instead. Beam is far to complicated for it’s use case. Migrations can be run with &lt;a href=&quot;https://hackage.haskell.org/package/postgresql-migration&quot;&gt;postgresql-migration&lt;/a&gt; for example, using the suggested migrations from persistent. I’d only recommend using beam for hobby projects or as a case study for &lt;a href=&quot;https://okmij.org/ftp/tagless-final/JFP.pdf&quot;&gt;finally tagless&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No need to read a book to use Haskell! This post will get you going with a serious web application while only sticking to the concepts that are encountered. This is a Haskell safari with as end goal a working webapp with database.&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-simple-servant.md&quot;&gt;Pragmatic Haskell: Simple servant web server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-message-servant.md&quot;&gt;Pragmatic Haskell II: IO Webservant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-database.md&quot;&gt;Pragmatic Haskell III: Beam Postgres DB&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2018/haskell-beam-postgres.svg&quot; alt=&quot;fancy db image&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;fancy db image&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Web applications need to store data. In the &lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-message-servant.md&quot;&gt;previous blog post&lt;/a&gt; we did this in a file for simplicity. Now we will use something more appropriate: A relational database. The beam library is used for this because it is closest to the “ORM” way of thinking: Model a schema, generate SQL to query that schema, and have migrations to move between different versions of that schema. Migrations are left for another post for simplicity.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;#complete-sources&quot;&gt;For the inpatient: Resulting source&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;preparation&quot;&gt;Preparation&lt;/h1&gt;
&lt;p&gt;Unfortunately this post requires us to do quite a bit of devops to get started. We need to:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;Install Postgres&lt;/li&gt;
&lt;li&gt;Create a user&lt;/li&gt;
&lt;li&gt;Create db&lt;/li&gt;
&lt;li&gt;Populate structure&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Installing Postgres is out of the scope of this post. We sidestep using migrations for with the &lt;code&gt;data_model.sql&lt;/code&gt; file &lt;a href=&quot;#data_modelsql&quot;&gt;(see sources)&lt;/a&gt;. Use the following commands to prepare the database:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-u&lt;/span&gt; postgres createuser &lt;span class=&quot;at&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;$USER&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;dropdb&lt;/span&gt; awesome_db&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;createdb&lt;/span&gt; awesome_db&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;psql&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-f&lt;/span&gt; ./data_model.sql &lt;span class=&quot;at&quot;&gt;-d&lt;/span&gt; awesome_db&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Congratulations, devops was survived. Note that using this sql file is not idiomatic to beam. The schema should be managed by beam, but getting migrations to function is currently hard (it’s a work in progress).&lt;/p&gt;
&lt;h1 id=&quot;creating-structure&quot;&gt;Creating structure&lt;/h1&gt;
&lt;p&gt;The beam library models our desired structure at type level. This is done in a separate file called &lt;code&gt;DB.hs&lt;/code&gt;. It can be seen in &lt;a href=&quot;#dbhs&quot;&gt;the sources&lt;/a&gt;. With help of this code beam can inspect the definitions, and it also provides type safety for the beam sql domain specific language. In other words if the migrations work there would be a path towards bringing the database up to date with the code base, or a compile error. This is very pleasant because we get a thight feedback loop. Now let us carefully inspect that file to understand it.&lt;/p&gt;
&lt;h2 id=&quot;language-extensions&quot;&gt;Language extensions&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE DeriveGeneric         #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE FlexibleInstances     #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;#cb2-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE MultiParamTypeClasses #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;#cb2-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE OverloadedStrings     #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;#cb2-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE StandaloneDeriving    #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;#cb2-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE TypeFamilies          #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;#cb2-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE DuplicateRecordFields #-}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This looks daunting however these extensions are individually quite simple. Generally they either make nicer API’s or an easier language to use. We will go over each of them.&lt;/p&gt;
&lt;h3 id=&quot;standalonederiving&quot;&gt;StandaloneDeriving&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;StandaloneDeriving&lt;/code&gt; allows us to use the derive mechanism outside of a data declaration, for example:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This mechanism allows deriving (automatic code generation) to be used more flexibly. In this case we want to do this because the &lt;code&gt;MessageT f&lt;/code&gt; type constructor to derive (as &lt;code&gt;f&lt;/code&gt; is unknown), but &lt;code&gt;MessageT Identity&lt;/code&gt; is known so we can derive that. The GHC &lt;a href=&quot;https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#stand-alone-deriving-declarations&quot;&gt;manual lists&lt;/a&gt; more possible reasons to derive like this instead of the standard method.&lt;/p&gt;
&lt;h3 id=&quot;typefamilies&quot;&gt;TypeFamilies&lt;/h3&gt;
&lt;p&gt;Type families allow us to declare &lt;code&gt;data&lt;/code&gt; inside an instance. The &lt;code&gt;Table&lt;/code&gt; class requires &lt;code&gt;TypeFamilies&lt;/code&gt; to instantiate because it needs a &lt;code&gt;data&lt;/code&gt; called primary key in it’s instance:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;#cb4-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Table&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;#cb4-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserId&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Columnar&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;#cb4-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    primaryKey &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserId&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; _id&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This example is a prime reason to use type families: It allows beam to assume the primary key exist for all tables.&lt;/p&gt;
&lt;p&gt;The Haskell &lt;a href=&quot;https://wiki.haskell.org/GHC/Type_families&quot;&gt;wiki&lt;/a&gt; goes more in depth on type families&lt;/p&gt;
&lt;h3 id=&quot;flexibleinstances&quot;&gt;FlexibleInstances&lt;/h3&gt;
&lt;p&gt;If we don’t enable &lt;code&gt;FlexibleInstances&lt;/code&gt; we get the following error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/home/jappie/projects/haskell/awesome-project-name/src/DB.hs:36:10: error:
    • Illegal instance declaration for ‘Beamable (PrimaryKey MessageT)’
        (All instance types must be of the form (T a1 ... an)
         where a1 ... an are *distinct type variables*,
         and each type variable appears at most once in the instance head.
         Use FlexibleInstances if you want to disable this.)
    • In the instance declaration for ‘Beamable (PrimaryKey MessageT)’
   |
36 | instance Beamable (PrimaryKey MessageT)
   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without Flexible instances parenthesis aren’t allowed. We know the parenthesis are the problem because the following line does not get an error:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;#cb6-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Beamable&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;multiparamtypeclasses&quot;&gt;MultiParamTypeClasses&lt;/h3&gt;
&lt;p&gt;If &lt;code&gt;MultiParamTypeClasses&lt;/code&gt; is disabled an error appears:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/home/jappie/projects/haskell/awesome-project-name/src/DB.hs:65:10: error:
    • Illegal instance declaration for ‘Database be AwesomeDb’
        (Only one type can be given in an instance head.
         Use MultiParamTypeClasses if you want to allow more, or zero.)
    • In the instance declaration for ‘Database be AwesomeDb’
   |
65 | instance Database be AwesomeDb
   |          ^^^^^^^^^^^^^^^^^^^^^&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because we use two parameters for this instance (&lt;code&gt;be&lt;/code&gt; and &lt;code&gt;AwesomeDb&lt;/code&gt;). By default Haskell only allows one.&lt;/p&gt;
&lt;h3 id=&quot;derivegeneric&quot;&gt;DeriveGeneric&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;DeriveGeneric&lt;/code&gt; was discussed in a &lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-simple-servant.md&quot;&gt;previous blog post&lt;/a&gt;. In short: &lt;code&gt;Generic&lt;/code&gt; allows for introspection of data structures using the fact any data structure can be modeled in a regular (generic) pattern.&lt;/p&gt;
&lt;h3 id=&quot;overloadedstrings&quot;&gt;OverloadedStrings&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;OverloadedStrings&lt;/code&gt; is probably the most common language extension. It converts string automatically, for example &lt;code&gt;String -&amp;gt; ByteString&lt;/code&gt;. In our case it’s only used for connection string:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;#cb8-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;connectionString ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;BS.ByteString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;#cb8-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;connectionString &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;dbname=awesome_db&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this case it inserts automatically a function &lt;code&gt;String -&amp;gt; ByteString&lt;/code&gt;. Using this extension avoids tedious conversions.&lt;/p&gt;
&lt;h3 id=&quot;duplicaterecordfields&quot;&gt;DuplicateRecordFields&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;DuplicateRecordFields&lt;/code&gt; allows creation of records with the same name. For example both user and messages have an &lt;code&gt;_id&lt;/code&gt; record. Because they have the same name, type annotations are used to determine which function is called, for example in:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;#cb9-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Table&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;#cb9-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserId&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Columnar&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;#cb9-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    primaryKey &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserId&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;_id ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;imports&quot;&gt;Imports&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;#cb10-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.ByteString&lt;/span&gt;                  &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;BS&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;ByteString is required for the type signature of connection string.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb11&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb11-1&quot;&gt;&lt;a href=&quot;#cb11-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Text&lt;/span&gt;                      &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Text is required for the column datatype.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;#cb12-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt;           &lt;span class=&quot;dt&quot;&gt;Database.Beam&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We import all of beam, for convenience. This entire module is a client of beam, there is no need for explicit imports.&lt;/p&gt;
&lt;h2 id=&quot;user-table&quot;&gt;User table&lt;/h2&gt;
&lt;p&gt;We start with defining the structure of our user table.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb13&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb13-1&quot;&gt;&lt;a href=&quot;#cb13-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-2&quot;&gt;&lt;a href=&quot;#cb13-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                {&lt;span class=&quot;ot&quot;&gt; _id     ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-3&quot;&gt;&lt;a href=&quot;#cb13-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                ,&lt;span class=&quot;ot&quot;&gt; _name   ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Text.Text&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-4&quot;&gt;&lt;a href=&quot;#cb13-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                ,&lt;span class=&quot;ot&quot;&gt; _email  ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Text.Text&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-5&quot;&gt;&lt;a href=&quot;#cb13-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                }&lt;/span&gt;
&lt;span id=&quot;cb13-6&quot;&gt;&lt;a href=&quot;#cb13-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What are these &lt;code&gt;C&lt;/code&gt; and &lt;code&gt;f&lt;/code&gt;’s doing here? The &lt;code&gt;C&lt;/code&gt; is an abbreviation for &lt;a href=&quot;http://hackage.haskell.org/package/beam-core-0.7.2.2/docs/Database-Beam-Schema.html#t:Columnar&quot;&gt;Columnar&lt;/a&gt;, which is a type that requires two other types to complete. In this case &lt;code&gt;C&lt;/code&gt; is given an &lt;code&gt;f&lt;/code&gt;, and a second argument with the actual type of the column. &lt;code&gt;f&lt;/code&gt; is not defined, instead it’s also an argument of &lt;code&gt;UserT&lt;/code&gt;, therefore &lt;code&gt;UserT&lt;/code&gt; is of kind &lt;code&gt;* -&amp;gt; *&lt;/code&gt;. What we know however is that this &lt;code&gt;f&lt;/code&gt; is the same for all columns in &lt;code&gt;UserT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now this &lt;code&gt;f&lt;/code&gt; can be thought of as a ‘gap’ that can be filled up with anything. This gap allows the beam library to inspect the structure we have defined, and therefore create a schema out of it and hold the data of a row. The &lt;a href=&quot;https://hackage.haskell.org/package/beam-0.3.0.0/docs/Database-Beam-Schema.html#g:2&quot;&gt;hackage page&lt;/a&gt; goes deeper into the definition.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb14-1&quot;&gt;&lt;a href=&quot;#cb14-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This defines a type alias. A userT with Identity is simply a user. In this case we are filling the &lt;code&gt;f&lt;/code&gt; with Identity, &lt;a href=&quot;http://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Functor-Identity.html&quot;&gt;a container&lt;/a&gt; that exposes on function &lt;code&gt;runIdentity&lt;/code&gt; which removes the container and does nothing with the content. This is usefull for the case where we want to have the user as a result from the database.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb15&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb15-1&quot;&gt;&lt;a href=&quot;#cb15-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb15-2&quot;&gt;&lt;a href=&quot;#cb15-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Implement the &lt;code&gt;show&lt;/code&gt; function automatically for the identity case and for the primary key which will be introduced below.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb16&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb16-1&quot;&gt;&lt;a href=&quot;#cb16-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Table&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-2&quot;&gt;&lt;a href=&quot;#cb16-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserId&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Columnar&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-3&quot;&gt;&lt;a href=&quot;#cb16-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    primaryKey &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserId&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;_id ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb16-4&quot;&gt;&lt;a href=&quot;#cb16-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserId&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- For convenience&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we make UserT an instance of a Table. To do this we must specify a PrimaryKey, of which we define the type in the data line. The next line tells which function must be used to access the primary key. In other words we implement the primaryKey function here by saying &lt;code&gt;_id&lt;/code&gt; must be used for it. We use a type annotation to indicate which &lt;code&gt;_id&lt;/code&gt; function is used. Leaving that out results in an ambigious type error.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb17&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb17-1&quot;&gt;&lt;a href=&quot;#cb17-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Beamable&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-2&quot;&gt;&lt;a href=&quot;#cb17-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Beamable&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Beamable&lt;/code&gt; provides several &lt;a href=&quot;http://hackage.haskell.org/package/beam-core-0.7.2.2/docs/Database-Beam-Schema.html#t:Beamable&quot;&gt;‘introspection routines’&lt;/a&gt;. We require it to create a &lt;code&gt;Database&lt;/code&gt; out of the table. The database will be described below.&lt;/p&gt;
&lt;h2 id=&quot;message-table&quot;&gt;Message table&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb18&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb18-1&quot;&gt;&lt;a href=&quot;#cb18-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-2&quot;&gt;&lt;a href=&quot;#cb18-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                {&lt;span class=&quot;ot&quot;&gt; _id        ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-3&quot;&gt;&lt;a href=&quot;#cb18-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                ,&lt;span class=&quot;ot&quot;&gt; _from      ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; f&lt;/span&gt;
&lt;span id=&quot;cb18-4&quot;&gt;&lt;a href=&quot;#cb18-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                ,&lt;span class=&quot;ot&quot;&gt; _content   ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Text.Text&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-5&quot;&gt;&lt;a href=&quot;#cb18-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                }&lt;/span&gt;
&lt;span id=&quot;cb18-6&quot;&gt;&lt;a href=&quot;#cb18-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-7&quot;&gt;&lt;a href=&quot;#cb18-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-8&quot;&gt;&lt;a href=&quot;#cb18-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb18-9&quot;&gt;&lt;a href=&quot;#cb18-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-10&quot;&gt;&lt;a href=&quot;#cb18-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-11&quot;&gt;&lt;a href=&quot;#cb18-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Table&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-12&quot;&gt;&lt;a href=&quot;#cb18-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageId&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Columnar&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-13&quot;&gt;&lt;a href=&quot;#cb18-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    primaryKey &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageId&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;_id ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb18-14&quot;&gt;&lt;a href=&quot;#cb18-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageId&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- For convenience&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-15&quot;&gt;&lt;a href=&quot;#cb18-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-16&quot;&gt;&lt;a href=&quot;#cb18-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Beamable&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-17&quot;&gt;&lt;a href=&quot;#cb18-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Beamable&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The boiler plate is similar to that of User, the only new concept is the from field, which points at the user table with the primary key. Beam can make joins on this with the DSL.&lt;/p&gt;
&lt;h2 id=&quot;database&quot;&gt;Database&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb19&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb19-1&quot;&gt;&lt;a href=&quot;#cb19-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AwesomeDb&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AwesomeDb&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-2&quot;&gt;&lt;a href=&quot;#cb19-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                      {&lt;span class=&quot;ot&quot;&gt; _users    ::&lt;/span&gt; f (&lt;span class=&quot;dt&quot;&gt;TableEntity&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb19-3&quot;&gt;&lt;a href=&quot;#cb19-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                      ,&lt;span class=&quot;ot&quot;&gt; _messages ::&lt;/span&gt; f (&lt;span class=&quot;dt&quot;&gt;TableEntity&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt;) }&lt;/span&gt;
&lt;span id=&quot;cb19-4&quot;&gt;&lt;a href=&quot;#cb19-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                        &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This type defines the entire database. Again it provides a ‘hole’ with the &lt;code&gt;f&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb20&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb20-1&quot;&gt;&lt;a href=&quot;#cb20-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;connectionString ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;BS.ByteString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-2&quot;&gt;&lt;a href=&quot;#cb20-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;connectionString &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;dbname=awesome_db&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;connectionString&lt;/code&gt; is required to connect to the database. One probably doesn’t want to hard code it, but for this guide hard coding is good enough.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb21&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb21-1&quot;&gt;&lt;a href=&quot;#cb21-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Database&lt;/span&gt; be &lt;span class=&quot;dt&quot;&gt;AwesomeDb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we create a beam database out of the AwesomeDB type. the &lt;code&gt;be&lt;/code&gt; hole is reserved for a back end, which we don’t specify.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb22&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb22-1&quot;&gt;&lt;a href=&quot;#cb22-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;awesomeDB ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DatabaseSettings&lt;/span&gt; be &lt;span class=&quot;dt&quot;&gt;AwesomeDb&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-2&quot;&gt;&lt;a href=&quot;#cb22-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;awesomeDB &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; defaultDbSettings&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The implementation of AwesomeDB just uses the default database settings. All structural information is already provided at type level.&lt;/p&gt;
&lt;h1 id=&quot;using-structure&quot;&gt;Using structure&lt;/h1&gt;
&lt;p&gt;Now we have a database structure defined we can use it in &lt;code&gt;Lib.hs&lt;/code&gt;. We have already seen most of this source file in the previous &lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-message-servant.md&quot;&gt;blog post&lt;/a&gt;, the new version can be seen in &lt;a href=&quot;#dbhs&quot;&gt;the sources&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The functionality is still the same except now we’re using a database as backend rather than a file. Just like with the previous post, the example shows both how to insert, as well as retrieve data. Let’s inspect the new changes.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb23&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb23-1&quot;&gt;&lt;a href=&quot;#cb23-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;messages ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Handler&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb23-2&quot;&gt;&lt;a href=&quot;#cb23-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;messages conn message &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb23-3&quot;&gt;&lt;a href=&quot;#cb23-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  messages &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; liftIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Messages will hold the resulting messages we’re to querying from the database. &lt;code&gt;liftIO&lt;/code&gt; allows functions within the &lt;code&gt;IO&lt;/code&gt; context (eg, interact with the world).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb24&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb24-1&quot;&gt;&lt;a href=&quot;#cb24-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    PgBeam.runBeamPostgres conn &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Run the beam Monad with help of a connection. In other words, everything within this do block is a query for the database, and we’re explicitly using postgres to solve ambiguity.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb25&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb25-1&quot;&gt;&lt;a href=&quot;#cb25-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; user &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; from message&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Retrieve the user from message for convenience.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb26&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb26-1&quot;&gt;&lt;a href=&quot;#cb26-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      [user] &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runInsertReturningList (DB._users DB.awesomeDB) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; Beam.insertExpressions [&lt;span class=&quot;dt&quot;&gt;DB.User&lt;/span&gt;{&lt;/span&gt;
&lt;span id=&quot;cb26-2&quot;&gt;&lt;a href=&quot;#cb26-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            DB._userId &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Beam.default_,&lt;/span&gt;
&lt;span id=&quot;cb26-3&quot;&gt;&lt;a href=&quot;#cb26-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            DB._name &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Beam.val_ (&lt;span class=&quot;fu&quot;&gt;pack&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; name &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; user ),&lt;/span&gt;
&lt;span id=&quot;cb26-4&quot;&gt;&lt;a href=&quot;#cb26-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            DB._email &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Beam.val_ (&lt;span class=&quot;fu&quot;&gt;pack&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; email &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; user )&lt;/span&gt;
&lt;span id=&quot;cb26-5&quot;&gt;&lt;a href=&quot;#cb26-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        }]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;the &lt;code&gt;runInsertReturningList&lt;/code&gt; function call is quite complex. The first argument defines in which table we’re using, we want to insert something into the users table. The second argument is a list of expressions. To get the expressions we use the &lt;code&gt;Beam.insertExpressions&lt;/code&gt; function. This is how we insert an item, in this case we only want to insert one user. We use the User constructor defined earlier in the &lt;code&gt;DB.hs&lt;/code&gt; module to obtain a user. The fields are populated with values or a special default value.&lt;/p&gt;
&lt;p&gt;Note that although this function is complex, if we do anything wrong we get a type error. Our code will not compile unless we do it right. This is one of the strengths of beam.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb27&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb27-1&quot;&gt;&lt;a href=&quot;#cb27-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      _ &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runInsertReturningList (DB._messages DB.awesomeDB) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; Beam.insertExpressions &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;DB.Message&lt;/span&gt;{&lt;/span&gt;
&lt;span id=&quot;cb27-2&quot;&gt;&lt;a href=&quot;#cb27-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            DB._messageId &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Beam.default_,&lt;/span&gt;
&lt;span id=&quot;cb27-3&quot;&gt;&lt;a href=&quot;#cb27-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            DB._from &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Beam.val_ (Beam.pk user),&lt;/span&gt;
&lt;span id=&quot;cb27-4&quot;&gt;&lt;a href=&quot;#cb27-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            DB._content &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Beam.val_ (&lt;span class=&quot;fu&quot;&gt;pack&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; content message)&lt;/span&gt;
&lt;span id=&quot;cb27-5&quot;&gt;&lt;a href=&quot;#cb27-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        }]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These lines insert the message into the db, linking it up with the newly inserted user trough the pk.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb28&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb28-1&quot;&gt;&lt;a href=&quot;#cb28-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      Beam.runSelectReturningList &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; Beam.select &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb28-2&quot;&gt;&lt;a href=&quot;#cb28-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        usr &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; (Beam.all_ (DB._users DB.awesomeDB))&lt;/span&gt;
&lt;span id=&quot;cb28-3&quot;&gt;&lt;a href=&quot;#cb28-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        msg &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; Beam.oneToMany_ (DB._messages DB.awesomeDB) DB._from usr&lt;/span&gt;
&lt;span id=&quot;cb28-4&quot;&gt;&lt;a href=&quot;#cb28-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (msg, usr)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This query gets the resulting messages and their respective users joined together.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb29&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb29-1&quot;&gt;&lt;a href=&quot;#cb29-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-2&quot;&gt;&lt;a href=&quot;#cb29-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (&lt;/span&gt;
&lt;span id=&quot;cb29-3&quot;&gt;&lt;a href=&quot;#cb29-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      \(msg, usr) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-4&quot;&gt;&lt;a href=&quot;#cb29-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        (&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-5&quot;&gt;&lt;a href=&quot;#cb29-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          (unpack &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; DB._name usr)&lt;/span&gt;
&lt;span id=&quot;cb29-6&quot;&gt;&lt;a href=&quot;#cb29-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          (unpack &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; DB._email usr))&lt;/span&gt;
&lt;span id=&quot;cb29-7&quot;&gt;&lt;a href=&quot;#cb29-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        (unpack &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; DB._content msg)&lt;/span&gt;
&lt;span id=&quot;cb29-8&quot;&gt;&lt;a href=&quot;#cb29-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ) messages&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;here we convert the database user and database message, to the ‘API’ user and ‘API’ messages. The reason we need to do this is because our database data structure does not implement &lt;code&gt;toJSON&lt;/code&gt;. Also the database structure has extra information such as the primary key which we may want to hide from API clients.&lt;/p&gt;
&lt;h1 id=&quot;execute&quot;&gt;Execute!&lt;/h1&gt;
&lt;p&gt;To run the program we use:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb30&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb30-1&quot;&gt;&lt;a href=&quot;#cb30-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;ex&quot;&gt;stack&lt;/span&gt; build&lt;/span&gt;
&lt;span id=&quot;cb30-2&quot;&gt;&lt;a href=&quot;#cb30-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;ex&quot;&gt;stack&lt;/span&gt; exec webservice&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To test it a simple curl request was made:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb31&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb31-1&quot;&gt;&lt;a href=&quot;#cb31-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;ex&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;--header&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Content-Type: application/json&amp;quot;&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;--data&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;{&amp;quot;from&amp;quot;:{&amp;quot;email&amp;quot;:&amp;quot;d&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;xyz&amp;quot;}, &amp;quot;content&amp;quot;: &amp;quot;does it word?&amp;quot;}&amp;#39;&lt;/span&gt; http://127.0.0.1:6868/message/ &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can inspect the database with postgres&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb32&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb32-1&quot;&gt;&lt;a href=&quot;#cb32-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;ex&quot;&gt;psql&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;dbname=awesome_db&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-2&quot;&gt;&lt;a href=&quot;#cb32-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;ex&quot;&gt;\dt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-3&quot;&gt;&lt;a href=&quot;#cb32-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;cf&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;ex&quot;&gt;*&lt;/span&gt; from messages&lt;span class=&quot;kw&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;We have looked at the beam library in this post and it’s interaction with postgres. Although the example is simple, there is quite a bit of boilerplate involved, but once setup it provides a complete type safe DSL to the database. With the database and web server in place nothing is stopping the reader from making his next major project in Haskell! We hereby conclude our Haskell safari successfully.&lt;/p&gt;
&lt;h1 id=&quot;complete-sources&quot;&gt;Complete sources&lt;/h1&gt;
&lt;p&gt;The complete sources can be found on &lt;a href=&quot;https://github.com/jappeace/awesome-project-name/tree/beam-postgre-no-migrate&quot;&gt;github&lt;/a&gt;, and below.&lt;/p&gt;
&lt;h2 id=&quot;db.hs&quot;&gt;Db.hs&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb33&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb33-1&quot;&gt;&lt;a href=&quot;#cb33-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE DeriveGeneric         #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-2&quot;&gt;&lt;a href=&quot;#cb33-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE FlexibleInstances     #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-3&quot;&gt;&lt;a href=&quot;#cb33-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE MultiParamTypeClasses #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-4&quot;&gt;&lt;a href=&quot;#cb33-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE OverloadedStrings     #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-5&quot;&gt;&lt;a href=&quot;#cb33-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE StandaloneDeriving    #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-6&quot;&gt;&lt;a href=&quot;#cb33-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE TypeFamilies          #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-7&quot;&gt;&lt;a href=&quot;#cb33-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE DuplicateRecordFields #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-8&quot;&gt;&lt;a href=&quot;#cb33-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-9&quot;&gt;&lt;a href=&quot;#cb33-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- | db structure and source of truth&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-10&quot;&gt;&lt;a href=&quot;#cb33-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DB&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-11&quot;&gt;&lt;a href=&quot;#cb33-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.ByteString&lt;/span&gt;                &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;BS&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-12&quot;&gt;&lt;a href=&quot;#cb33-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Text&lt;/span&gt;                      &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-13&quot;&gt;&lt;a href=&quot;#cb33-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt;           &lt;span class=&quot;dt&quot;&gt;Database.Beam&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-14&quot;&gt;&lt;a href=&quot;#cb33-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-15&quot;&gt;&lt;a href=&quot;#cb33-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-16&quot;&gt;&lt;a href=&quot;#cb33-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-17&quot;&gt;&lt;a href=&quot;#cb33-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                {&lt;span class=&quot;ot&quot;&gt; _id ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-18&quot;&gt;&lt;a href=&quot;#cb33-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                ,&lt;span class=&quot;ot&quot;&gt; _name   ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Text.Text&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-19&quot;&gt;&lt;a href=&quot;#cb33-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                ,&lt;span class=&quot;ot&quot;&gt; _email  ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Text.Text&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-20&quot;&gt;&lt;a href=&quot;#cb33-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                }&lt;/span&gt;
&lt;span id=&quot;cb33-21&quot;&gt;&lt;a href=&quot;#cb33-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-22&quot;&gt;&lt;a href=&quot;#cb33-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-23&quot;&gt;&lt;a href=&quot;#cb33-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserId&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-24&quot;&gt;&lt;a href=&quot;#cb33-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-25&quot;&gt;&lt;a href=&quot;#cb33-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-26&quot;&gt;&lt;a href=&quot;#cb33-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Table&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-27&quot;&gt;&lt;a href=&quot;#cb33-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserId&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Columnar&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-28&quot;&gt;&lt;a href=&quot;#cb33-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    primaryKey &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserId&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;_id ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb33-29&quot;&gt;&lt;a href=&quot;#cb33-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserId&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- For convenience&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-30&quot;&gt;&lt;a href=&quot;#cb33-30&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-31&quot;&gt;&lt;a href=&quot;#cb33-31&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Beamable&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-32&quot;&gt;&lt;a href=&quot;#cb33-32&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Beamable&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb33-33&quot;&gt;&lt;a href=&quot;#cb33-33&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-34&quot;&gt;&lt;a href=&quot;#cb33-34&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;/span&gt;
&lt;span id=&quot;cb33-35&quot;&gt;&lt;a href=&quot;#cb33-35&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-36&quot;&gt;&lt;a href=&quot;#cb33-36&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                {&lt;span class=&quot;ot&quot;&gt; _id ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-37&quot;&gt;&lt;a href=&quot;#cb33-37&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                ,&lt;span class=&quot;ot&quot;&gt; _from      ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt; f&lt;/span&gt;
&lt;span id=&quot;cb33-38&quot;&gt;&lt;a href=&quot;#cb33-38&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                ,&lt;span class=&quot;ot&quot;&gt; _content   ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Text.Text&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-39&quot;&gt;&lt;a href=&quot;#cb33-39&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                }&lt;/span&gt;
&lt;span id=&quot;cb33-40&quot;&gt;&lt;a href=&quot;#cb33-40&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-41&quot;&gt;&lt;a href=&quot;#cb33-41&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-42&quot;&gt;&lt;a href=&quot;#cb33-42&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb33-43&quot;&gt;&lt;a href=&quot;#cb33-43&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-44&quot;&gt;&lt;a href=&quot;#cb33-44&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-45&quot;&gt;&lt;a href=&quot;#cb33-45&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Table&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-46&quot;&gt;&lt;a href=&quot;#cb33-46&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageId&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Columnar&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-47&quot;&gt;&lt;a href=&quot;#cb33-47&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    primaryKey &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageId&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;_id ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;C&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb33-48&quot;&gt;&lt;a href=&quot;#cb33-48&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageId&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- For convenience&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-49&quot;&gt;&lt;a href=&quot;#cb33-49&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-50&quot;&gt;&lt;a href=&quot;#cb33-50&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Beamable&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-51&quot;&gt;&lt;a href=&quot;#cb33-51&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Beamable&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PrimaryKey&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb33-52&quot;&gt;&lt;a href=&quot;#cb33-52&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-53&quot;&gt;&lt;a href=&quot;#cb33-53&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-54&quot;&gt;&lt;a href=&quot;#cb33-54&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AwesomeDb&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AwesomeDb&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-55&quot;&gt;&lt;a href=&quot;#cb33-55&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                      {&lt;span class=&quot;ot&quot;&gt; _ausers    ::&lt;/span&gt; f (&lt;span class=&quot;dt&quot;&gt;TableEntity&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserT&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb33-56&quot;&gt;&lt;a href=&quot;#cb33-56&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                      ,&lt;span class=&quot;ot&quot;&gt; _messages ::&lt;/span&gt; f (&lt;span class=&quot;dt&quot;&gt;TableEntity&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MessageT&lt;/span&gt;) }&lt;/span&gt;
&lt;span id=&quot;cb33-57&quot;&gt;&lt;a href=&quot;#cb33-57&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                        &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-58&quot;&gt;&lt;a href=&quot;#cb33-58&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-59&quot;&gt;&lt;a href=&quot;#cb33-59&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;connectionString ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;BS.ByteString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-60&quot;&gt;&lt;a href=&quot;#cb33-60&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;connectionString &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;dbname=awesome_db&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-61&quot;&gt;&lt;a href=&quot;#cb33-61&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-62&quot;&gt;&lt;a href=&quot;#cb33-62&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Database&lt;/span&gt; be &lt;span class=&quot;dt&quot;&gt;AwesomeDb&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-63&quot;&gt;&lt;a href=&quot;#cb33-63&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-64&quot;&gt;&lt;a href=&quot;#cb33-64&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;awesomeDB ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DatabaseSettings&lt;/span&gt; be &lt;span class=&quot;dt&quot;&gt;AwesomeDb&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-65&quot;&gt;&lt;a href=&quot;#cb33-65&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;awesomeDB &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; defaultDbSettings&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;lib.hs&quot;&gt;Lib.hs&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb34&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb34-1&quot;&gt;&lt;a href=&quot;#cb34-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE DataKinds #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-2&quot;&gt;&lt;a href=&quot;#cb34-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE TypeOperators #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-3&quot;&gt;&lt;a href=&quot;#cb34-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE DeriveGeneric #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-4&quot;&gt;&lt;a href=&quot;#cb34-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-5&quot;&gt;&lt;a href=&quot;#cb34-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lib&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-6&quot;&gt;&lt;a href=&quot;#cb34-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( webAppEntry&lt;/span&gt;
&lt;span id=&quot;cb34-7&quot;&gt;&lt;a href=&quot;#cb34-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-8&quot;&gt;&lt;a href=&quot;#cb34-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-9&quot;&gt;&lt;a href=&quot;#cb34-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Servant&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-10&quot;&gt;&lt;a href=&quot;#cb34-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Control.Monad.IO.Class&lt;/span&gt;(liftIO)&lt;/span&gt;
&lt;span id=&quot;cb34-11&quot;&gt;&lt;a href=&quot;#cb34-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.ByteString.Lazy&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LBS&lt;/span&gt; (writeFile, readFile) &lt;/span&gt;
&lt;span id=&quot;cb34-12&quot;&gt;&lt;a href=&quot;#cb34-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Aeson&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;FromJSON&lt;/span&gt;, encode, decode)&lt;/span&gt;
&lt;span id=&quot;cb34-13&quot;&gt;&lt;a href=&quot;#cb34-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;GHC.Generics&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb34-14&quot;&gt;&lt;a href=&quot;#cb34-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Network.Wai&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;Application&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb34-15&quot;&gt;&lt;a href=&quot;#cb34-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Network.Wai.Handler.Warp&lt;/span&gt;(run)&lt;/span&gt;
&lt;span id=&quot;cb34-16&quot;&gt;&lt;a href=&quot;#cb34-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt;           &lt;span class=&quot;dt&quot;&gt;Database.PostgreSQL.Simple&lt;/span&gt;   (&lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb34-17&quot;&gt;&lt;a href=&quot;#cb34-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DB&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DB&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-18&quot;&gt;&lt;a href=&quot;#cb34-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt;           &lt;span class=&quot;dt&quot;&gt;Database.Beam.Backend.SQL.BeamExtensions&lt;/span&gt; (runInsertReturningList)&lt;/span&gt;
&lt;span id=&quot;cb34-19&quot;&gt;&lt;a href=&quot;#cb34-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-20&quot;&gt;&lt;a href=&quot;#cb34-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Database.Beam&lt;/span&gt;                            &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Beam&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-21&quot;&gt;&lt;a href=&quot;#cb34-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Database.Beam.Postgres&lt;/span&gt;                            &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PgBeam&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-22&quot;&gt;&lt;a href=&quot;#cb34-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Text&lt;/span&gt;(pack, unpack)&lt;/span&gt;
&lt;span id=&quot;cb34-23&quot;&gt;&lt;a href=&quot;#cb34-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-24&quot;&gt;&lt;a href=&quot;#cb34-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserAPI&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;users&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Get&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] [&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb34-25&quot;&gt;&lt;a href=&quot;#cb34-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ReqBody&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Post&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] [&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb34-26&quot;&gt;&lt;a href=&quot;#cb34-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-27&quot;&gt;&lt;a href=&quot;#cb34-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; {&lt;/span&gt;
&lt;span id=&quot;cb34-28&quot;&gt;&lt;a href=&quot;#cb34-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  from ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb34-29&quot;&gt;&lt;a href=&quot;#cb34-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  content ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-30&quot;&gt;&lt;a href=&quot;#cb34-30&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;} &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb34-31&quot;&gt;&lt;a href=&quot;#cb34-31&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-32&quot;&gt;&lt;a href=&quot;#cb34-32&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-33&quot;&gt;&lt;a href=&quot;#cb34-33&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-34&quot;&gt;&lt;a href=&quot;#cb34-34&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-35&quot;&gt;&lt;a href=&quot;#cb34-35&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-36&quot;&gt;&lt;a href=&quot;#cb34-36&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; name ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-37&quot;&gt;&lt;a href=&quot;#cb34-37&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; email ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-38&quot;&gt;&lt;a href=&quot;#cb34-38&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  } &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb34-39&quot;&gt;&lt;a href=&quot;#cb34-39&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-40&quot;&gt;&lt;a href=&quot;#cb34-40&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-41&quot;&gt;&lt;a href=&quot;#cb34-41&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-42&quot;&gt;&lt;a href=&quot;#cb34-42&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-43&quot;&gt;&lt;a href=&quot;#cb34-43&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;users ::&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb34-44&quot;&gt;&lt;a href=&quot;#cb34-44&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;users &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-45&quot;&gt;&lt;a href=&quot;#cb34-45&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  [ &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Isaac Newton&amp;quot;&lt;/span&gt;    &lt;span class=&quot;st&quot;&gt;&amp;quot;isaac@newton.co.uk&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-46&quot;&gt;&lt;a href=&quot;#cb34-46&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  , &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Albert Einstein&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;ae@mc2.org&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-47&quot;&gt;&lt;a href=&quot;#cb34-47&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ]&lt;/span&gt;
&lt;span id=&quot;cb34-48&quot;&gt;&lt;a href=&quot;#cb34-48&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-49&quot;&gt;&lt;a href=&quot;#cb34-49&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;messages ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Handler&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb34-50&quot;&gt;&lt;a href=&quot;#cb34-50&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;messages conn message &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb34-51&quot;&gt;&lt;a href=&quot;#cb34-51&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  messages &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; liftIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb34-52&quot;&gt;&lt;a href=&quot;#cb34-52&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    PgBeam.runBeamPostgres conn &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-53&quot;&gt;&lt;a href=&quot;#cb34-53&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; user &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; from message&lt;/span&gt;
&lt;span id=&quot;cb34-54&quot;&gt;&lt;a href=&quot;#cb34-54&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      [user] &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runInsertReturningList (DB._ausers DB.awesomeDB) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb34-55&quot;&gt;&lt;a href=&quot;#cb34-55&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          Beam.insertExpressions [&lt;span class=&quot;dt&quot;&gt;DB.User&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb34-56&quot;&gt;&lt;a href=&quot;#cb34-56&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            Beam.default_&lt;/span&gt;
&lt;span id=&quot;cb34-57&quot;&gt;&lt;a href=&quot;#cb34-57&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            (Beam.val_ (&lt;span class=&quot;fu&quot;&gt;pack&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; name &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; user ))&lt;/span&gt;
&lt;span id=&quot;cb34-58&quot;&gt;&lt;a href=&quot;#cb34-58&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            (Beam.val_ (&lt;span class=&quot;fu&quot;&gt;pack&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; email &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; user ))&lt;/span&gt;
&lt;span id=&quot;cb34-59&quot;&gt;&lt;a href=&quot;#cb34-59&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id=&quot;cb34-60&quot;&gt;&lt;a href=&quot;#cb34-60&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      _ &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runInsertReturningList (DB._messages DB.awesomeDB) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb34-61&quot;&gt;&lt;a href=&quot;#cb34-61&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          Beam.insertExpressions &lt;/span&gt;
&lt;span id=&quot;cb34-62&quot;&gt;&lt;a href=&quot;#cb34-62&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            [&lt;span class=&quot;dt&quot;&gt;DB.Message&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb34-63&quot;&gt;&lt;a href=&quot;#cb34-63&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;              Beam.default_ &lt;/span&gt;
&lt;span id=&quot;cb34-64&quot;&gt;&lt;a href=&quot;#cb34-64&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;              (Beam.val_ (Beam.pk user))&lt;/span&gt;
&lt;span id=&quot;cb34-65&quot;&gt;&lt;a href=&quot;#cb34-65&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;              (Beam.val_ (&lt;span class=&quot;fu&quot;&gt;pack&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; content message))&lt;/span&gt;
&lt;span id=&quot;cb34-66&quot;&gt;&lt;a href=&quot;#cb34-66&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            ]&lt;/span&gt;
&lt;span id=&quot;cb34-67&quot;&gt;&lt;a href=&quot;#cb34-67&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      Beam.runSelectReturningList &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; Beam.select &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb34-68&quot;&gt;&lt;a href=&quot;#cb34-68&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        usr &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; (Beam.all_ (DB._ausers DB.awesomeDB))&lt;/span&gt;
&lt;span id=&quot;cb34-69&quot;&gt;&lt;a href=&quot;#cb34-69&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        msg &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; Beam.oneToMany_ (DB._messages DB.awesomeDB) DB._from usr&lt;/span&gt;
&lt;span id=&quot;cb34-70&quot;&gt;&lt;a href=&quot;#cb34-70&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (msg, usr)&lt;/span&gt;
&lt;span id=&quot;cb34-71&quot;&gt;&lt;a href=&quot;#cb34-71&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-72&quot;&gt;&lt;a href=&quot;#cb34-72&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (&lt;/span&gt;
&lt;span id=&quot;cb34-73&quot;&gt;&lt;a href=&quot;#cb34-73&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      \(msg, usr) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-74&quot;&gt;&lt;a href=&quot;#cb34-74&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        (&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-75&quot;&gt;&lt;a href=&quot;#cb34-75&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          (unpack &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; DB._name usr)&lt;/span&gt;
&lt;span id=&quot;cb34-76&quot;&gt;&lt;a href=&quot;#cb34-76&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          (unpack &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; DB._email usr))&lt;/span&gt;
&lt;span id=&quot;cb34-77&quot;&gt;&lt;a href=&quot;#cb34-77&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        (unpack &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; DB._content msg)&lt;/span&gt;
&lt;span id=&quot;cb34-78&quot;&gt;&lt;a href=&quot;#cb34-78&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ) messages&lt;/span&gt;
&lt;span id=&quot;cb34-79&quot;&gt;&lt;a href=&quot;#cb34-79&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-80&quot;&gt;&lt;a href=&quot;#cb34-80&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-81&quot;&gt;&lt;a href=&quot;#cb34-81&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;server ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserAPI&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-82&quot;&gt;&lt;a href=&quot;#cb34-82&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;server conn&lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; users) &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; (messages conn)&lt;/span&gt;
&lt;span id=&quot;cb34-83&quot;&gt;&lt;a href=&quot;#cb34-83&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-84&quot;&gt;&lt;a href=&quot;#cb34-84&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;userAPI ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserAPI&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-85&quot;&gt;&lt;a href=&quot;#cb34-85&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;userAPI &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-86&quot;&gt;&lt;a href=&quot;#cb34-86&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-87&quot;&gt;&lt;a href=&quot;#cb34-87&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;app ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Application&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-88&quot;&gt;&lt;a href=&quot;#cb34-88&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;app conn &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; serve userAPI (server conn)&lt;/span&gt;
&lt;span id=&quot;cb34-89&quot;&gt;&lt;a href=&quot;#cb34-89&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-90&quot;&gt;&lt;a href=&quot;#cb34-90&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;webAppEntry ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb34-91&quot;&gt;&lt;a href=&quot;#cb34-91&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;webAppEntry conn &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-92&quot;&gt;&lt;a href=&quot;#cb34-92&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  run &lt;span class=&quot;dv&quot;&gt;6868&lt;/span&gt; (app conn)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;data_model.sql&quot;&gt;data_model.sql&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb35&quot;&gt;&lt;pre class=&quot;sourceCode sql&quot;&gt;&lt;code class=&quot;sourceCode sql&quot;&gt;&lt;span id=&quot;cb35-1&quot;&gt;&lt;a href=&quot;#cb35-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;TABLE&lt;/span&gt; ausers &lt;span class=&quot;kw&quot;&gt;cascade&lt;/span&gt;;&lt;/span&gt;
&lt;span id=&quot;cb35-2&quot;&gt;&lt;a href=&quot;#cb35-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;TABLE&lt;/span&gt; messages &lt;span class=&quot;kw&quot;&gt;cascade&lt;/span&gt;;&lt;/span&gt;
&lt;span id=&quot;cb35-3&quot;&gt;&lt;a href=&quot;#cb35-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;TABLE&lt;/span&gt; ausers (&lt;/span&gt;
&lt;span id=&quot;cb35-4&quot;&gt;&lt;a href=&quot;#cb35-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt; serial &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;KEY&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb35-5&quot;&gt;&lt;a href=&quot;#cb35-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;varchar&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb35-6&quot;&gt;&lt;a href=&quot;#cb35-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    email &lt;span class=&quot;dt&quot;&gt;varchar&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb35-7&quot;&gt;&lt;a href=&quot;#cb35-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;);&lt;/span&gt;
&lt;span id=&quot;cb35-8&quot;&gt;&lt;a href=&quot;#cb35-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb35-9&quot;&gt;&lt;a href=&quot;#cb35-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;TABLE&lt;/span&gt; messages (&lt;/span&gt;
&lt;span id=&quot;cb35-10&quot;&gt;&lt;a href=&quot;#cb35-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt; serial &lt;span class=&quot;kw&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;KEY&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb35-11&quot;&gt;&lt;a href=&quot;#cb35-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    from__id &lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;REFERENCES&lt;/span&gt; ausers(&lt;span class=&quot;kw&quot;&gt;id&lt;/span&gt;),&lt;/span&gt;
&lt;span id=&quot;cb35-12&quot;&gt;&lt;a href=&quot;#cb35-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    content &lt;span class=&quot;dt&quot;&gt;varchar&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;NULL&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb35-13&quot;&gt;&lt;a href=&quot;#cb35-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Pragmatic Haskell II: IO Webservant</title>
    <link href="https://jappieklooster.nl/pragmatic-haskell-ii-io-webservant.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2018-06-27:/pragmatic-haskell-ii-io-webservant.html</id>
    <published>2018-06-27T22:00:00Z</published>
    <updated>2019-10-24T18:34:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-simple-servant.md&quot;&gt;Pragmatic Haskell: Simple servant web server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-message-servant.md&quot;&gt;Pragmatic Haskell II: IO Webservant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-database.md&quot;&gt;Pragmatic Haskell III: Beam Postgres DB&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Most Haskell language guides will leave IO &lt;a href=&quot;http://www.seas.upenn.edu/%7Ecis194/spring13/lectures/08-IO.html&quot;&gt;until&lt;/a&gt; &lt;a href=&quot;http://learnyouahaskell.com/input-and-output&quot;&gt;later&lt;/a&gt;. This guide is different, this guide is about &lt;em&gt;using&lt;/em&gt; Haskell. Our focus is different: We build first, then learn trough &lt;a href=&quot;https://medium.com/the-polymath-project/programming-for-personal-growth-64052e407894&quot;&gt;delight&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2018/io-webserver.svg&quot; alt=&quot;Fancy intro image&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Fancy&lt;/figcaption&gt;&lt;/figure&gt;</summary>
    <content type="html">&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-simple-servant.md&quot;&gt;Pragmatic Haskell: Simple servant web server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-message-servant.md&quot;&gt;Pragmatic Haskell II: IO Webservant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-database.md&quot;&gt;Pragmatic Haskell III: Beam Postgres DB&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Most Haskell language guides will leave IO &lt;a href=&quot;http://www.seas.upenn.edu/%7Ecis194/spring13/lectures/08-IO.html&quot;&gt;until&lt;/a&gt; &lt;a href=&quot;http://learnyouahaskell.com/input-and-output&quot;&gt;later&lt;/a&gt;. This guide is different, this guide is about &lt;em&gt;using&lt;/em&gt; Haskell. Our focus is different: We build first, then learn trough &lt;a href=&quot;https://medium.com/the-polymath-project/programming-for-personal-growth-64052e407894&quot;&gt;delight&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2018/io-webserver.svg&quot; alt=&quot;Fancy intro image&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Fancy intro image&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-simple-servant.md&quot;&gt;previous blog&lt;/a&gt; post explained how to get going with a simple minimalist servant web server. In this blog post the simple web server will get an extra REST endpoint that can do IO actions. This is an important part of pragmatic Haskell programming. Without IO our program can do nothing. Programmers are not theorists, therefore we need IO.&lt;/p&gt;
&lt;h1 id=&quot;preparation&quot;&gt;Preparation&lt;/h1&gt;
&lt;p&gt;To keep things simple, the code assumes a file exists. Create one with an empty JSON array in the project root:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;bu&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;[]&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; messages.txt&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Bytestrings are a convenient way of opening files and putting the results into &lt;code&gt;aeson&lt;/code&gt;, the JSON library. Dealing with bytestrings requires another dependency:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; base &amp;gt;= 4.7 &amp;amp;&amp;amp; &amp;lt; 5&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;#cb2-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; servant-server&lt;/span&gt;&lt;span class=&quot;co&quot;&gt; # http server&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;#cb2-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; aeson&lt;/span&gt;&lt;span class=&quot;co&quot;&gt; # json&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;#cb2-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; wai&lt;/span&gt;&lt;span class=&quot;co&quot;&gt; # web application (interface)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;#cb2-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; warp&lt;/span&gt;&lt;span class=&quot;co&quot;&gt; # web application implementation&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;#cb2-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; bytestring&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1 id=&quot;a-lot-of-code&quot;&gt;A lot of code&lt;/h1&gt;
&lt;p&gt;These are the &lt;s&gt;magic spells&lt;/s&gt; changes which add an endpoint, explained in detail below:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE DataKinds #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;#cb3-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE TypeOperators #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;#cb3-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE DeriveGeneric #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;#cb3-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-5&quot;&gt;&lt;a href=&quot;#cb3-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lib&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-6&quot;&gt;&lt;a href=&quot;#cb3-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( webAppEntry&lt;/span&gt;
&lt;span id=&quot;cb3-7&quot;&gt;&lt;a href=&quot;#cb3-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-8&quot;&gt;&lt;a href=&quot;#cb3-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-9&quot;&gt;&lt;a href=&quot;#cb3-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Servant&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-10&quot;&gt;&lt;a href=&quot;#cb3-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Control.Monad.IO.Class&lt;/span&gt;(liftIO)&lt;/span&gt;
&lt;span id=&quot;cb3-11&quot;&gt;&lt;a href=&quot;#cb3-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.ByteString.Lazy&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LBS&lt;/span&gt; (writeFile, readFile) &lt;/span&gt;
&lt;span id=&quot;cb3-12&quot;&gt;&lt;a href=&quot;#cb3-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Aeson&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;FromJSON&lt;/span&gt;, encode, decode)&lt;/span&gt;
&lt;span id=&quot;cb3-13&quot;&gt;&lt;a href=&quot;#cb3-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;GHC.Generics&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb3-14&quot;&gt;&lt;a href=&quot;#cb3-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Network.Wai&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;Application&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb3-15&quot;&gt;&lt;a href=&quot;#cb3-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Network.Wai.Handler.Warp&lt;/span&gt;(run)&lt;/span&gt;
&lt;span id=&quot;cb3-16&quot;&gt;&lt;a href=&quot;#cb3-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Maybe&lt;/span&gt; (fromMaybe)&lt;/span&gt;
&lt;span id=&quot;cb3-17&quot;&gt;&lt;a href=&quot;#cb3-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-18&quot;&gt;&lt;a href=&quot;#cb3-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserAPI&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;users&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Get&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] [&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb3-19&quot;&gt;&lt;a href=&quot;#cb3-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ReqBody&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Post&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] [&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb3-20&quot;&gt;&lt;a href=&quot;#cb3-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-21&quot;&gt;&lt;a href=&quot;#cb3-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; {&lt;/span&gt;
&lt;span id=&quot;cb3-22&quot;&gt;&lt;a href=&quot;#cb3-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  from ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb3-23&quot;&gt;&lt;a href=&quot;#cb3-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  content ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-24&quot;&gt;&lt;a href=&quot;#cb3-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;} &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb3-25&quot;&gt;&lt;a href=&quot;#cb3-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-26&quot;&gt;&lt;a href=&quot;#cb3-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-27&quot;&gt;&lt;a href=&quot;#cb3-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-28&quot;&gt;&lt;a href=&quot;#cb3-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-29&quot;&gt;&lt;a href=&quot;#cb3-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-30&quot;&gt;&lt;a href=&quot;#cb3-30&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; name ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-31&quot;&gt;&lt;a href=&quot;#cb3-31&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; email ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-32&quot;&gt;&lt;a href=&quot;#cb3-32&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  } &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb3-33&quot;&gt;&lt;a href=&quot;#cb3-33&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-34&quot;&gt;&lt;a href=&quot;#cb3-34&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-35&quot;&gt;&lt;a href=&quot;#cb3-35&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-36&quot;&gt;&lt;a href=&quot;#cb3-36&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-37&quot;&gt;&lt;a href=&quot;#cb3-37&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;users ::&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb3-38&quot;&gt;&lt;a href=&quot;#cb3-38&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;users &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-39&quot;&gt;&lt;a href=&quot;#cb3-39&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  [ &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Isaac Newton&amp;quot;&lt;/span&gt;    &lt;span class=&quot;st&quot;&gt;&amp;quot;isaac@newton.co.uk&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-40&quot;&gt;&lt;a href=&quot;#cb3-40&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  , &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Albert Einstein&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;ae@mc2.org&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-41&quot;&gt;&lt;a href=&quot;#cb3-41&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ]&lt;/span&gt;
&lt;span id=&quot;cb3-42&quot;&gt;&lt;a href=&quot;#cb3-42&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;messageFile ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-43&quot;&gt;&lt;a href=&quot;#cb3-43&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;messageFile &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;messages.txt&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-44&quot;&gt;&lt;a href=&quot;#cb3-44&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-45&quot;&gt;&lt;a href=&quot;#cb3-45&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;messages ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Handler&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb3-46&quot;&gt;&lt;a href=&quot;#cb3-46&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;messages message &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;cb3-47&quot;&gt;&lt;a href=&quot;#cb3-47&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  result &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; liftIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; LBS.readFile messageFile&lt;/span&gt;
&lt;span id=&quot;cb3-48&quot;&gt;&lt;a href=&quot;#cb3-48&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; decode result &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-49&quot;&gt;&lt;a href=&quot;#cb3-49&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; []&lt;/span&gt;
&lt;span id=&quot;cb3-50&quot;&gt;&lt;a href=&quot;#cb3-50&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-51&quot;&gt;&lt;a href=&quot;#cb3-51&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; contents &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;++&lt;/span&gt; [message]&lt;/span&gt;
&lt;span id=&quot;cb3-52&quot;&gt;&lt;a href=&quot;#cb3-52&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      liftIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; LBS.writeFile messageFile (encode contents)&lt;/span&gt;
&lt;span id=&quot;cb3-53&quot;&gt;&lt;a href=&quot;#cb3-53&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; contents&lt;/span&gt;
&lt;span id=&quot;cb3-54&quot;&gt;&lt;a href=&quot;#cb3-54&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-55&quot;&gt;&lt;a href=&quot;#cb3-55&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;server ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserAPI&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-56&quot;&gt;&lt;a href=&quot;#cb3-56&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;server &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; users) &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; messages&lt;/span&gt;
&lt;span id=&quot;cb3-57&quot;&gt;&lt;a href=&quot;#cb3-57&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-58&quot;&gt;&lt;a href=&quot;#cb3-58&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;userAPI ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserAPI&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-59&quot;&gt;&lt;a href=&quot;#cb3-59&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;userAPI &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-60&quot;&gt;&lt;a href=&quot;#cb3-60&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-61&quot;&gt;&lt;a href=&quot;#cb3-61&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;app ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Application&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-62&quot;&gt;&lt;a href=&quot;#cb3-62&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;app &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; serve userAPI server&lt;/span&gt;
&lt;span id=&quot;cb3-63&quot;&gt;&lt;a href=&quot;#cb3-63&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-64&quot;&gt;&lt;a href=&quot;#cb3-64&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;webAppEntry ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb3-65&quot;&gt;&lt;a href=&quot;#cb3-65&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;webAppEntry &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; run &lt;span class=&quot;dv&quot;&gt;6868&lt;/span&gt; app&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will setup another endpoint for messages. The new endpoint will accept a post request under “/message”. It will write the message to a file and then it will return the contents of that file.&lt;/p&gt;
&lt;h1 id=&quot;line-by-line-inspection&quot;&gt;Line by line inspection&lt;/h1&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;#cb4-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserAPI&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;users&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Get&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] [&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;#cb4-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ReqBody&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Post&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] [&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;a href=&quot;http://hackage.haskell.org/package/servant-0.14/docs/Servant-API-Alternative.html#t::-60--124--62-&quot;&gt;&lt;code&gt;:&amp;lt;|&amp;gt;&lt;/code&gt; operator&lt;/a&gt; is used to add an extra endpoint. It combines the two endpoints into one. In these lines, we are constructing something akin to a jump table. The decleration of this operator is surprisingly simple:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; a &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; a &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Left sign of equality is used for type, right side for data construction. Skimming over this, like true Haskellers we will ignore the &lt;a href=&quot;http://hackage.haskell.org/package/servant-0.14/docs/src/Servant-API-Alternative.html#%3A%3C%7C%3E&quot;&gt;inner workings&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;The extra end point “message” is similar in structure to the existing “user” endpoint. If read like a sentence “message” is a POST only endpoint, which accepts a Message JSON body, and it returns a list of Messages in JSON.&lt;/p&gt;
&lt;h2 id=&quot;message-data&quot;&gt;Message data&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;#cb6-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; {&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;#cb6-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  from ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;#cb6-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  content ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;#cb6-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;} &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;#cb6-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-6&quot;&gt;&lt;a href=&quot;#cb6-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-7&quot;&gt;&lt;a href=&quot;#cb6-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is Message, apparently it’s from a &lt;code&gt;User&lt;/code&gt; and has some content &lt;code&gt;String&lt;/code&gt;. Aside from using another data type inside an existing data type, no new concepts are introduced.&lt;/p&gt;
&lt;h2 id=&quot;file-path&quot;&gt;File path&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;#cb7-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;messageFile ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The type &lt;code&gt;FilePath&lt;/code&gt; is just an alias for a &lt;code&gt;String&lt;/code&gt;: &lt;code&gt;type FilePath = String&lt;/code&gt;. In other words we can use them interchangeably. &lt;code&gt;FilePath&lt;/code&gt; acts as documentation.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;#cb8-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;messageFile &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;messages.txt&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is where we define what file name is used.&lt;/p&gt;
&lt;h2 id=&quot;message-handler&quot;&gt;Message handler&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;#cb9-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;messages ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Handler&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Message&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We define a Handler (which is an servant api endpoint). It requires a message, then it will return a list of messages within a &lt;code&gt;Handler&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;do-notation&quot;&gt;Do notation&lt;/h3&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;#cb10-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;messages message &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt; &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The do keyword allows us to code with &lt;a href=&quot;https://en.wikibooks.org/wiki/Haskell/do_notation&quot;&gt;do notation&lt;/a&gt;. This allows us to do assignments with &lt;code&gt;&amp;lt;-&lt;/code&gt; (not assignment, but close enough). This only works when the result container is a &lt;a href=&quot;https://wiki.haskell.org/Monad&quot;&gt;Monad&lt;/a&gt;. &lt;em&gt;How&lt;/em&gt; monads work is a mystery, but usage is simple: Use do notation.&lt;/p&gt;
&lt;h3 id=&quot;liftio&quot;&gt;LiftIO&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;  result &amp;lt;- liftIO $ LBS.readFile messageFile&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we read the message file as a lazy bytestring and put it into the result. One may wonder why we are using liftIO, if it’s deleted we get this:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;#cb12-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;/home/jappie/projects/haskell/awesome-project-name/src/Lib.hs:46:13:&lt;/span&gt; error:&lt;/span&gt;
&lt;span id=&quot;cb12-2&quot;&gt;&lt;a href=&quot;#cb12-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ex&quot;&gt;•&lt;/span&gt; Couldnt match type ‘IO’ with ‘Handler’&lt;/span&gt;
&lt;span id=&quot;cb12-3&quot;&gt;&lt;a href=&quot;#cb12-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ex&quot;&gt;Expected&lt;/span&gt; type: Handler Data.ByteString.Lazy.Internal.ByteString&lt;/span&gt;
&lt;span id=&quot;cb12-4&quot;&gt;&lt;a href=&quot;#cb12-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;ex&quot;&gt;Actual&lt;/span&gt; type: IO Data.ByteString.Lazy.Internal.ByteString&lt;/span&gt;
&lt;span id=&quot;cb12-5&quot;&gt;&lt;a href=&quot;#cb12-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ex&quot;&gt;•&lt;/span&gt; In a stmt of a &lt;span class=&quot;st&quot;&gt;&amp;#39;do&amp;#39;&lt;/span&gt; block: result &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;- LBS.readFile messageFile&lt;/span&gt;
&lt;span id=&quot;cb12-6&quot;&gt;&lt;a href=&quot;#cb12-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ex&quot;&gt;In&lt;/span&gt; the expression:&lt;/span&gt;
&lt;span id=&quot;cb12-7&quot;&gt;&lt;a href=&quot;#cb12-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;ex&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;- LBS.readFile messageFile&lt;/span&gt;
&lt;span id=&quot;cb12-8&quot;&gt;&lt;a href=&quot;#cb12-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           &lt;span class=&quot;cf&quot;&gt;case&lt;/span&gt; decode result of&lt;/span&gt;
&lt;span id=&quot;cb12-9&quot;&gt;&lt;a href=&quot;#cb12-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;             Nothing -&amp;gt; pure []&lt;/span&gt;
&lt;span id=&quot;cb12-10&quot;&gt;&lt;a href=&quot;#cb12-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;             Just x -&amp;gt; do ...&lt;/span&gt;
&lt;span id=&quot;cb12-11&quot;&gt;&lt;a href=&quot;#cb12-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      In an equation for ‘messages’:&lt;/span&gt;
&lt;span id=&quot;cb12-12&quot;&gt;&lt;a href=&quot;#cb12-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          messages message&lt;/span&gt;
&lt;span id=&quot;cb12-13&quot;&gt;&lt;a href=&quot;#cb12-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            = do result &amp;lt;- LBS.readFile messageFile&lt;/span&gt;
&lt;span id=&quot;cb12-14&quot;&gt;&lt;a href=&quot;#cb12-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                 case decode result of&lt;/span&gt;
&lt;span id=&quot;cb12-15&quot;&gt;&lt;a href=&quot;#cb12-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                   Nothing -&amp;gt; pure ...&lt;/span&gt;
&lt;span id=&quot;cb12-16&quot;&gt;&lt;a href=&quot;#cb12-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                   Just x -&amp;gt; ...&lt;/span&gt;
&lt;span id=&quot;cb12-17&quot;&gt;&lt;a href=&quot;#cb12-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   |&lt;/span&gt;
&lt;span id=&quot;cb12-18&quot;&gt;&lt;a href=&quot;#cb12-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;46 |   result &amp;lt;- LBS.readFile messageFile&lt;/span&gt;
&lt;span id=&quot;cb12-19&quot;&gt;&lt;a href=&quot;#cb12-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   |             ^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;LBS.readfile&lt;/code&gt; function has a return type of &lt;code&gt;IO&lt;/code&gt;. However the return type of &lt;code&gt;messages&lt;/code&gt; is &lt;code&gt;Handler&lt;/code&gt;. Therefore the compiler says that it expects &lt;code&gt;Handler&lt;/code&gt;, but the actual type is &lt;code&gt;IO&lt;/code&gt;. Handler implements the &lt;code&gt;MonadIO&lt;/code&gt; typeclass however, which allows &lt;code&gt;IO&lt;/code&gt; by calling the &lt;code&gt;liftIO&lt;/code&gt; function. The &lt;code&gt;liftIO&lt;/code&gt; function simply tells the Handler container to execute some function within the &lt;code&gt;IO&lt;/code&gt; container.&lt;/p&gt;
&lt;p&gt;The dollar sign can be replaced with an open parentheses, which is closed at the end of the line. This is equivalent for example:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb13&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb13-1&quot;&gt;&lt;a href=&quot;#cb13-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;liftIO (LBS.readFile messageFile)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As said before &lt;code&gt;&amp;lt;-&lt;/code&gt; is (basically) used for assignment in do notation, using &lt;code&gt;&amp;lt;-&lt;/code&gt; is a good way to get rid of a monad container. &lt;code&gt;result&lt;/code&gt; now contains the contents of messageFile, the IO is being evaluated and removed by the &lt;code&gt;&amp;lt;-&lt;/code&gt; operator. In Haskell a lot of wrapping and unwrapping is done.&lt;/p&gt;
&lt;h3 id=&quot;case-..-of&quot;&gt;Case .. of&lt;/h3&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb14-1&quot;&gt;&lt;a href=&quot;#cb14-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; decode result &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we’re decoding the contents of &lt;code&gt;result&lt;/code&gt;. decoding JSON may not succeed and therefore the library authors of &lt;code&gt;aeson&lt;/code&gt; made &lt;a href=&quot;http://hackage.haskell.org/package/aeson-1.4.0.0/docs/Data-Aeson.html#v:decode&quot;&gt;decode&lt;/a&gt; return a maybe container:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb15&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb15-1&quot;&gt;&lt;a href=&quot;#cb15-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;decode ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromJSON&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ByteString&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; a &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this signature, &lt;code&gt;a&lt;/code&gt; can be anything as long as it implements FromJSON. We fulfill this condition with generic and &lt;code&gt;instance FromJSON Message&lt;/code&gt;. We give as bytestring the &lt;code&gt;result&lt;/code&gt; to decode, in return it gives us &lt;code&gt;Maybe a&lt;/code&gt;. The compiler deduces that &lt;code&gt;a&lt;/code&gt; in this case is &lt;code&gt;[Message]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The return value will have content if decoding succeeded (&lt;code&gt;Just&lt;/code&gt;), or it won’t if it fails (&lt;code&gt;Nothing&lt;/code&gt;). To get rid of the container we pattern match it. This can be thought of as a switch case statement in other languages.&lt;/p&gt;
&lt;h4 id=&quot;nothing&quot;&gt;Nothing&lt;/h4&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb16&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb16-1&quot;&gt;&lt;a href=&quot;#cb16-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; []&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this case decoding fails. An empty list is returned to the client. We still must wrap this list in a &lt;code&gt;Handler&lt;/code&gt;, pure is used for that. Note that &lt;code&gt;pure == return&lt;/code&gt;. These functions both exist for &lt;a href=&quot;https://stackoverflow.com/questions/32788082/difference-between-return-and-pure&quot;&gt;historical reasons&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;just-a&quot;&gt;Just a&lt;/h4&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb17&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb17-1&quot;&gt;&lt;a href=&quot;#cb17-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this case there is success, the result is taken and put into x, after which another do block starts.&lt;/p&gt;
&lt;h3 id=&quot;let&quot;&gt;Let&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;      let contents = x ++ [message]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unlike the &lt;code&gt;&amp;lt;-&lt;/code&gt; operator, let does not do any unwrapping. We can see what happens if we replace the let binding by &lt;code&gt;contents &amp;lt;- x ++ [message]&lt;/code&gt;, the errors are:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb19&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb19-1&quot;&gt;&lt;a href=&quot;#cb19-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;/home/jappie/projects/haskell/awesome-project-name/src/Lib.hs:50:19:&lt;/span&gt; error:&lt;/span&gt;
&lt;span id=&quot;cb19-2&quot;&gt;&lt;a href=&quot;#cb19-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ex&quot;&gt;•&lt;/span&gt; Couldnt match type ‘[]’ with ‘Handler’&lt;/span&gt;
&lt;span id=&quot;cb19-3&quot;&gt;&lt;a href=&quot;#cb19-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ex&quot;&gt;Expected&lt;/span&gt; type: Handler Message&lt;/span&gt;
&lt;span id=&quot;cb19-4&quot;&gt;&lt;a href=&quot;#cb19-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;ex&quot;&gt;Actual&lt;/span&gt; type: &lt;span class=&quot;pp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-5&quot;&gt;&lt;a href=&quot;#cb19-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ex&quot;&gt;•&lt;/span&gt; In a stmt of a &lt;span class=&quot;st&quot;&gt;&amp;#39;do&amp;#39;&lt;/span&gt; block: contents &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;- x ++ &lt;span class=&quot;pp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-6&quot;&gt;&lt;a href=&quot;#cb19-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ex&quot;&gt;In&lt;/span&gt; the expression:&lt;/span&gt;
&lt;span id=&quot;cb19-7&quot;&gt;&lt;a href=&quot;#cb19-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;ex&quot;&gt;contents&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;- x ++ &lt;span class=&quot;pp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-8&quot;&gt;&lt;a href=&quot;#cb19-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           &lt;span class=&quot;ex&quot;&gt;liftIO&lt;/span&gt; $ LBS.writeFile messageFile &lt;span class=&quot;er&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ex&quot;&gt;encode&lt;/span&gt; contents&lt;span class=&quot;kw&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-9&quot;&gt;&lt;a href=&quot;#cb19-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;ex&quot;&gt;contents&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-10&quot;&gt;&lt;a href=&quot;#cb19-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ex&quot;&gt;In&lt;/span&gt; a case alternative:&lt;/span&gt;
&lt;span id=&quot;cb19-11&quot;&gt;&lt;a href=&quot;#cb19-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ex&quot;&gt;Just&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb19-12&quot;&gt;&lt;a href=&quot;#cb19-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ex&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; do contents &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;- x ++ &lt;span class=&quot;pp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-13&quot;&gt;&lt;a href=&quot;#cb19-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;ex&quot;&gt;liftIO&lt;/span&gt; $ LBS.writeFile messageFile &lt;span class=&quot;er&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ex&quot;&gt;encode&lt;/span&gt; contents&lt;span class=&quot;kw&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-14&quot;&gt;&lt;a href=&quot;#cb19-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;ex&quot;&gt;contents&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-15&quot;&gt;&lt;a href=&quot;#cb19-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-16&quot;&gt;&lt;a href=&quot;#cb19-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt;       &lt;span class=&quot;ex&quot;&gt;contents&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;- x ++ &lt;span class=&quot;pp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-17&quot;&gt;&lt;a href=&quot;#cb19-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt;                   &lt;span class=&quot;ex&quot;&gt;^^^^^^^^^^^^^^&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-18&quot;&gt;&lt;a href=&quot;#cb19-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-19&quot;&gt;&lt;a href=&quot;#cb19-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;/home/jappie/projects/haskell/awesome-project-name/src/Lib.hs:52:7:&lt;/span&gt; error:&lt;/span&gt;
&lt;span id=&quot;cb19-20&quot;&gt;&lt;a href=&quot;#cb19-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ex&quot;&gt;•&lt;/span&gt; Couldnt match type ‘Message’ with ‘&lt;span class=&quot;pp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;]&lt;/span&gt;’&lt;/span&gt;
&lt;span id=&quot;cb19-21&quot;&gt;&lt;a href=&quot;#cb19-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ex&quot;&gt;Expected&lt;/span&gt; type: Handler &lt;span class=&quot;pp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-22&quot;&gt;&lt;a href=&quot;#cb19-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;ex&quot;&gt;Actual&lt;/span&gt; type: Handler Message&lt;/span&gt;
&lt;span id=&quot;cb19-23&quot;&gt;&lt;a href=&quot;#cb19-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ex&quot;&gt;•&lt;/span&gt; In a stmt of a &lt;span class=&quot;st&quot;&gt;&amp;#39;do&amp;#39;&lt;/span&gt; block: return contents&lt;/span&gt;
&lt;span id=&quot;cb19-24&quot;&gt;&lt;a href=&quot;#cb19-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ex&quot;&gt;In&lt;/span&gt; the expression:&lt;/span&gt;
&lt;span id=&quot;cb19-25&quot;&gt;&lt;a href=&quot;#cb19-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;ex&quot;&gt;contents&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;- x ++ &lt;span class=&quot;pp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-26&quot;&gt;&lt;a href=&quot;#cb19-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           &lt;span class=&quot;ex&quot;&gt;liftIO&lt;/span&gt; $ LBS.writeFile messageFile &lt;span class=&quot;er&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ex&quot;&gt;encode&lt;/span&gt; contents&lt;span class=&quot;kw&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-27&quot;&gt;&lt;a href=&quot;#cb19-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;ex&quot;&gt;contents&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-28&quot;&gt;&lt;a href=&quot;#cb19-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ex&quot;&gt;In&lt;/span&gt; a case alternative:&lt;/span&gt;
&lt;span id=&quot;cb19-29&quot;&gt;&lt;a href=&quot;#cb19-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ex&quot;&gt;Just&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb19-30&quot;&gt;&lt;a href=&quot;#cb19-30&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ex&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; do contents &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;- x ++ &lt;span class=&quot;pp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-31&quot;&gt;&lt;a href=&quot;#cb19-31&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;ex&quot;&gt;liftIO&lt;/span&gt; $ LBS.writeFile messageFile &lt;span class=&quot;er&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ex&quot;&gt;encode&lt;/span&gt; contents&lt;span class=&quot;kw&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-32&quot;&gt;&lt;a href=&quot;#cb19-32&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;ex&quot;&gt;contents&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-33&quot;&gt;&lt;a href=&quot;#cb19-33&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-34&quot;&gt;&lt;a href=&quot;#cb19-34&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;52&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt;       &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;ex&quot;&gt;contents&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-35&quot;&gt;&lt;a href=&quot;#cb19-35&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt;       &lt;span class=&quot;ex&quot;&gt;^^^^^^^^^^^^^^^&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the first error the compiler says that a list is not a &lt;code&gt;Handler&lt;/code&gt; container. Which we expect because the return type of this function is &lt;code&gt;Handler [Message]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The second error assumes &lt;code&gt;contents&lt;/code&gt; is of the correct type, since &lt;code&gt;&amp;lt;-&lt;/code&gt; unwraps &lt;code&gt;contents&lt;/code&gt; would be of type &lt;code&gt;Message&lt;/code&gt;. The return type does not fit in this case either, we would get &lt;code&gt;Handler Message&lt;/code&gt; instead of &lt;code&gt;Handler [Message]&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;write&quot;&gt;Write&lt;/h3&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb20&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb20-1&quot;&gt;&lt;a href=&quot;#cb20-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      liftIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; LBS.writeFile messageFile (encode contents)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We encode the contents, then we write it to the message file in an IO effect. Type safety ensures encoding always succeeds.&lt;/p&gt;
&lt;h3 id=&quot;return&quot;&gt;Return&lt;/h3&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb21&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb21-1&quot;&gt;&lt;a href=&quot;#cb21-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; contents&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally we wrap the contents in a &lt;code&gt;Handler&lt;/code&gt; type.&lt;/p&gt;
&lt;h2 id=&quot;adding-the-handler-to-the-routes-map&quot;&gt;Adding the handler to the routes map&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb22&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb22-1&quot;&gt;&lt;a href=&quot;#cb22-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;server ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserAPI&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-2&quot;&gt;&lt;a href=&quot;#cb22-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;server &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; users) &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; messages&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is the implementation of the &lt;code&gt;UserAPI&lt;/code&gt; type described before. We use the same operator to also add the messages handler into the server. We don’t need to put &lt;code&gt;messages&lt;/code&gt; in a container with pure because the functions’ return type is already a &lt;code&gt;Handler&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Something worth pointing out is that this construction is in order, if we pull it out of order we would get a type level. Changing the line into:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb23&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb23-1&quot;&gt;&lt;a href=&quot;#cb23-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;server &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;  messages &lt;span class=&quot;op&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; users)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Will cause an error:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb24&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb24-1&quot;&gt;&lt;a href=&quot;#cb24-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;/home/jappie/projects/haskell/awesome-project-name/src/Lib.hs:55:11:&lt;/span&gt; error:&lt;/span&gt;
&lt;span id=&quot;cb24-2&quot;&gt;&lt;a href=&quot;#cb24-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ex&quot;&gt;•&lt;/span&gt; Could not match type ‘&lt;span class=&quot;pp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;]&lt;/span&gt;’ with ‘Handler &lt;span class=&quot;pp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;]&lt;/span&gt;’&lt;/span&gt;
&lt;span id=&quot;cb24-3&quot;&gt;&lt;a href=&quot;#cb24-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ex&quot;&gt;Expected&lt;/span&gt; type: Server UserAPI&lt;/span&gt;
&lt;span id=&quot;cb24-4&quot;&gt;&lt;a href=&quot;#cb24-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;ex&quot;&gt;Actual&lt;/span&gt; type: &lt;span class=&quot;er&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ex&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; Handler &lt;span class=&quot;pp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-5&quot;&gt;&lt;a href=&quot;#cb24-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                     &lt;span class=&quot;bu&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ex&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;pp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-6&quot;&gt;&lt;a href=&quot;#cb24-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ex&quot;&gt;•&lt;/span&gt; In the expression: messages :&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ex&quot;&gt;pure&lt;/span&gt; users&lt;span class=&quot;kw&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-7&quot;&gt;&lt;a href=&quot;#cb24-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ex&quot;&gt;In&lt;/span&gt; an equation for ‘server’: server = messages :&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ex&quot;&gt;pure&lt;/span&gt; users&lt;span class=&quot;kw&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-8&quot;&gt;&lt;a href=&quot;#cb24-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-9&quot;&gt;&lt;a href=&quot;#cb24-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;55&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;ex&quot;&gt;server&lt;/span&gt; =  messages :&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ex&quot;&gt;pure&lt;/span&gt; users&lt;span class=&quot;kw&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-10&quot;&gt;&lt;a href=&quot;#cb24-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt;           &lt;span class=&quot;ex&quot;&gt;^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1 id=&quot;execute-it&quot;&gt;Execute it!&lt;/h1&gt;
&lt;pre class=&quot;shell&quot;&gt;&lt;code&gt;curl --header &amp;quot;Content-Type: application/json&amp;quot; \ 
  --request POST \
  --data &amp;#39;{&amp;quot;from&amp;quot;:{&amp;quot;email&amp;quot;:&amp;quot;d&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;xyz&amp;quot;}, &amp;quot;content&amp;quot;: &amp;quot;does it word?&amp;quot;}&amp;#39; \
  http://localhost:6868/message&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Worked on this machine…&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2018/machine-on-fire.svg&quot; alt=&quot;Worked on my machine, lol, now we use IO everything is over&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Worked on my machine, lol, now we use IO everything is over&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Perhaps that’s why the theorists avoid IO 🤔.&lt;/p&gt;
&lt;h1 id=&quot;in-conclusion&quot;&gt;In conclusion&lt;/h1&gt;
&lt;p&gt;Without going into much theory, we dealt with &lt;code&gt;IO&lt;/code&gt;. For example we saw that haskell is about dealing with containers, to put certain functions in &lt;code&gt;IO&lt;/code&gt; rather than the return type, one uses &lt;code&gt;liftIO&lt;/code&gt;. &lt;code&gt;do&lt;/code&gt; notation was also encountered, which makes working with monads easier. Now we can affect the world with our programs trough IO!&lt;/p&gt;
&lt;p&gt;The complete code can be found &lt;a href=&quot;https://github.com/jappeace/awesome-project-name/tree/message-servant&quot;&gt;here&lt;/a&gt;. In the future we shall attach this simple web server to a database.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Pragmatic Haskell: Simple servant web server</title>
    <link href="https://jappieklooster.nl/pragmatic-haskell-simple-servant-web-server.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2018-06-25:/pragmatic-haskell-simple-servant-web-server.html</id>
    <published>2018-06-25T15:25:00Z</published>
    <updated>2018-06-25T15:25:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-simple-servant.md&quot;&gt;Pragmatic Haskell: Simple servant web server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-message-servant.md&quot;&gt;Pragmatic Haskell II: IO Webservant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-database.md&quot;&gt;Pragmatic Haskell III: Beam Postgres DB&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There are many &lt;a href=&quot;https://github.com/bitemyapp/learnhaskell&quot;&gt;guides available&lt;/a&gt; for learning Haskell. Setting up a something simple like a web server isn’t so straight forward. Perhaps choosing one of the &lt;a href=&quot;https://wiki.haskell.org/Web/Frameworks&quot;&gt;14 libraries&lt;/a&gt; is a bit much.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2018/haskell-sucks.jpg&quot; alt=&quot;Type level hell: Haskell sucks&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Type&lt;/figcaption&gt;&lt;/figure&gt;</summary>
    <content type="html">&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-simple-servant.md&quot;&gt;Pragmatic Haskell: Simple servant web server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-message-servant.md&quot;&gt;Pragmatic Haskell II: IO Webservant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;%7Bfilename%7D/pragmatic-haskell-database.md&quot;&gt;Pragmatic Haskell III: Beam Postgres DB&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There are many &lt;a href=&quot;https://github.com/bitemyapp/learnhaskell&quot;&gt;guides available&lt;/a&gt; for learning Haskell. Setting up a something simple like a web server isn’t so straight forward. Perhaps choosing one of the &lt;a href=&quot;https://wiki.haskell.org/Web/Frameworks&quot;&gt;14 libraries&lt;/a&gt; is a bit much.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2018/haskell-sucks.jpg&quot; alt=&quot;Type level hell: Haskell sucks&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Type level hell: Haskell sucks&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This guide will give opinionated web server start. This guide assumes no experience with Haskell, and will get you up to speed with a (REST) web server called &lt;a href=&quot;http://haskell-servant.readthedocs.io/en/stable/&quot;&gt;Servant&lt;/a&gt;. Servant is a good choice as it can describe both a server and client API. In the future this guide may be used as a foundation to create something more meaningful than just a very basic REST API, this will provide a good starting point however. Basic UNIX (command line) skills are assumed.&lt;/p&gt;
&lt;h1 id=&quot;from-nothing-start-with-build-tools&quot;&gt;From nothing, start with build tools&lt;/h1&gt;
&lt;p&gt;Install stack:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-sSL&lt;/span&gt; https://get.haskellstack.org/ &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Only attempt shortly to install it trough a package manager. There are other Haskell build tools, they will be more difficult in use. There is also the possibility for fully reproducible builds at a system level (nix). Which is out of the scope of this guide.&lt;/p&gt;
&lt;p&gt;Now setup a new project:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;#cb2-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;stack&lt;/span&gt; new awesome-project-name &lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;#cb2-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;bu&quot;&gt;cd&lt;/span&gt; awesome-project-name&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1 id=&quot;hello-world-with-stack&quot;&gt;Hello world with stack&lt;/h1&gt;
&lt;p&gt;Appreciate what happens when this is build:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;stack&lt;/span&gt; build &lt;span class=&quot;kw&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;ex&quot;&gt;stack&lt;/span&gt; exec awesome-project-name-exe&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This should build successfully and output &lt;code&gt;someFunc&lt;/code&gt;. Open up &lt;code&gt;src/Lib.hs&lt;/code&gt; with one’s favorite editor. This contains a few lines, created by stack:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;#cb4-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lib&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;#cb4-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( someFunc&lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;#cb4-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-4&quot;&gt;&lt;a href=&quot;#cb4-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-5&quot;&gt;&lt;a href=&quot;#cb4-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;someFunc ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb4-6&quot;&gt;&lt;a href=&quot;#cb4-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;someFunc &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;putStrLn&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;someFunc&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is where the &lt;code&gt;someFunc&lt;/code&gt; output came from when the program was ran. Change it to something a bit more appropriate, and rename the function too:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lib&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;#cb5-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( webAppEntry&lt;/span&gt;
&lt;span id=&quot;cb5-3&quot;&gt;&lt;a href=&quot;#cb5-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-4&quot;&gt;&lt;a href=&quot;#cb5-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-5&quot;&gt;&lt;a href=&quot;#cb5-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;webAppEntry ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb5-6&quot;&gt;&lt;a href=&quot;#cb5-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;webAppEntry &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;putStrLn&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;This is the beginning of my greetings to world&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Does it compile?&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;#cb6-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;stack&lt;/span&gt; build &lt;span class=&quot;kw&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;ex&quot;&gt;stack&lt;/span&gt; exec awesome-project-name-exe&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;#cb6-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;#cb6-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;/home/jappie/projects/haskell/awesome-project-name/app/Main.hs:6:8:&lt;/span&gt; error: Variable not in scope: someFunc :: IO &lt;span class=&quot;er&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;#cb6-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ex&quot;&gt;\|&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;#cb6-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;\|&lt;/span&gt; main = someFunc&lt;/span&gt;
&lt;span id=&quot;cb6-6&quot;&gt;&lt;a href=&quot;#cb6-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ex&quot;&gt;\|&lt;/span&gt;        ^^^^^^^^&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It does not compile. There is an app folder where by default all the executable reside (which is where the error occurs), and a &lt;code&gt;src&lt;/code&gt; folder where the library code lives (the modified file is in there). One can future proving themselves by putting as much code in the library as is reasonable.&lt;/p&gt;
&lt;p&gt;Fix the error in &lt;code&gt;app/Main.hs&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;#cb7-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Main&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;#cb7-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;#cb7-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lib&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;#cb7-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-5&quot;&gt;&lt;a href=&quot;#cb7-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;main ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb7-6&quot;&gt;&lt;a href=&quot;#cb7-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;main &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; webAppEntry&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It builds! Functions can be renamed, simple compile errors can be solved, and strings can be changed. Progress!&lt;/p&gt;
&lt;h1 id=&quot;servant-your-first-dependencies&quot;&gt;Servant: Your first dependencies&lt;/h1&gt;
&lt;p&gt;For the impatient, there is a minimal example already &lt;a href=&quot;https://github.com/haskell-servant/example-servant-minimal&quot;&gt;available&lt;/a&gt; by the library author. This guide will explain how to get there step by step. In &lt;code&gt;./package.yaml&lt;/code&gt;, on line 22 there is a &lt;code&gt;dependencies&lt;/code&gt; key, add &lt;code&gt;servant-server&lt;/code&gt;, &lt;code&gt;aeson&lt;/code&gt;, &lt;code&gt;wai&lt;/code&gt; and &lt;code&gt;warp&lt;/code&gt; to it like this:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;#cb8-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;#cb8-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; base &amp;gt;= 4.7 &amp;amp;&amp;amp; &amp;lt; 5&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;#cb8-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; servant-server&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-4&quot;&gt;&lt;a href=&quot;#cb8-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; aeson&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-5&quot;&gt;&lt;a href=&quot;#cb8-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; wai&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-6&quot;&gt;&lt;a href=&quot;#cb8-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; warp &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It may seem strange to immediately add four new dependencies, however this is because Haskell libraries are setup to be flexible. Even small projects grow quickly to have into the twenties of dependencies. Code reuse is not &lt;a href=&quot;https://www.youtube.com/watch?v=Jn3kdTaa69U&quot;&gt;a myth&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;servant-server&lt;/code&gt; is the &lt;a href=&quot;http://haskell-servant.readthedocs.io/en/stable/&quot;&gt;servant web server&lt;/a&gt;. &lt;a href=&quot;http://hackage.haskell.org/package/aeson&quot;&gt;&lt;code&gt;aeson&lt;/code&gt;&lt;/a&gt; is for JSON parsing and producing. &lt;a href=&quot;http://hackage.haskell.org/package/wai&quot;&gt;&lt;code&gt;wai&lt;/code&gt;&lt;/a&gt; is a web application interface and &lt;a href=&quot;http://hackage.haskell.org/package/warp&quot;&gt;&lt;code&gt;warp&lt;/code&gt;&lt;/a&gt; uses &lt;code&gt;wai&lt;/code&gt; to implement a web application (it binds to the port).&lt;/p&gt;
&lt;p&gt;Ensure that that this is done at the root of the yaml file (no indentation). Stack provides a way of specifying dependencies of either the executable or library. If its done on line 22, the root of the yaml file, it will be a dependency for everything in the project.&lt;/p&gt;
&lt;h1 id=&quot;a-minimal-servant&quot;&gt;A minimal servant&lt;/h1&gt;
&lt;p&gt;A good start is going to servants’ &lt;a href=&quot;http://hackage.haskell.org/package/servant&quot;&gt;Hackage&lt;/a&gt; page, which linked to a &lt;a href=&quot;http://haskell-servant.readthedocs.io/en/stable/tutorial/index.html&quot;&gt;tutorial&lt;/a&gt;. Servant does API definition &lt;a href=&quot;http://haskell-servant.readthedocs.io/en/stable/tutorial/ApiType.html&quot;&gt;at type level&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If it’s unknown to the reader what a type is, think of it as describing the shape of a function. Functions of different shapes don’t fit together, and won’t compile. What servant allows us to do is define this shape for a REST API. To gain a deeper understanding of this a concrete example will be inspected line by line. First all lines are listed for a minimal servant (&lt;code&gt;Lib.hs&lt;/code&gt;) server:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;#cb9-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE DataKinds #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;#cb9-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE TypeOperators #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;#cb9-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE DeriveGeneric #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-4&quot;&gt;&lt;a href=&quot;#cb9-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-5&quot;&gt;&lt;a href=&quot;#cb9-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lib&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-6&quot;&gt;&lt;a href=&quot;#cb9-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( webAppEntry&lt;/span&gt;
&lt;span id=&quot;cb9-7&quot;&gt;&lt;a href=&quot;#cb9-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-8&quot;&gt;&lt;a href=&quot;#cb9-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-9&quot;&gt;&lt;a href=&quot;#cb9-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Servant&lt;/span&gt;(serve, &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt;(..), &lt;span class=&quot;dt&quot;&gt;Server&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Get&lt;/span&gt;, (:&amp;gt;))&lt;/span&gt;
&lt;span id=&quot;cb9-10&quot;&gt;&lt;a href=&quot;#cb9-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Aeson&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb9-11&quot;&gt;&lt;a href=&quot;#cb9-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;GHC.Generics&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb9-12&quot;&gt;&lt;a href=&quot;#cb9-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Network.Wai&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;Application&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb9-13&quot;&gt;&lt;a href=&quot;#cb9-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Network.Wai.Handler.Warp&lt;/span&gt;(run)&lt;/span&gt;
&lt;span id=&quot;cb9-14&quot;&gt;&lt;a href=&quot;#cb9-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-15&quot;&gt;&lt;a href=&quot;#cb9-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserAPI&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;users&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Get&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] [&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb9-16&quot;&gt;&lt;a href=&quot;#cb9-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-17&quot;&gt;&lt;a href=&quot;#cb9-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-18&quot;&gt;&lt;a href=&quot;#cb9-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; name ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-19&quot;&gt;&lt;a href=&quot;#cb9-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; email ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-20&quot;&gt;&lt;a href=&quot;#cb9-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  } &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb9-21&quot;&gt;&lt;a href=&quot;#cb9-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-22&quot;&gt;&lt;a href=&quot;#cb9-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-23&quot;&gt;&lt;a href=&quot;#cb9-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-24&quot;&gt;&lt;a href=&quot;#cb9-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;users ::&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb9-25&quot;&gt;&lt;a href=&quot;#cb9-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;users &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-26&quot;&gt;&lt;a href=&quot;#cb9-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  [ &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Isaac Newton&amp;quot;&lt;/span&gt;    &lt;span class=&quot;st&quot;&gt;&amp;quot;isaac@newton.co.uk&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-27&quot;&gt;&lt;a href=&quot;#cb9-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  , &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Albert Einstein&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;ae@mc2.org&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-28&quot;&gt;&lt;a href=&quot;#cb9-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ]&lt;/span&gt;
&lt;span id=&quot;cb9-29&quot;&gt;&lt;a href=&quot;#cb9-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-30&quot;&gt;&lt;a href=&quot;#cb9-30&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;server ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserAPI&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-31&quot;&gt;&lt;a href=&quot;#cb9-31&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;server &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; users&lt;/span&gt;
&lt;span id=&quot;cb9-32&quot;&gt;&lt;a href=&quot;#cb9-32&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-33&quot;&gt;&lt;a href=&quot;#cb9-33&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;userAPI ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserAPI&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-34&quot;&gt;&lt;a href=&quot;#cb9-34&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;userAPI &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-35&quot;&gt;&lt;a href=&quot;#cb9-35&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-36&quot;&gt;&lt;a href=&quot;#cb9-36&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;app ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Application&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-37&quot;&gt;&lt;a href=&quot;#cb9-37&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;app &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; serve userAPI server&lt;/span&gt;
&lt;span id=&quot;cb9-38&quot;&gt;&lt;a href=&quot;#cb9-38&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-39&quot;&gt;&lt;a href=&quot;#cb9-39&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;webAppEntry ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb9-40&quot;&gt;&lt;a href=&quot;#cb9-40&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;webAppEntry &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; run &lt;span class=&quot;dv&quot;&gt;6868&lt;/span&gt; app&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;language-extensions&quot;&gt;Language extensions&lt;/h2&gt;
&lt;p&gt;The first three lines are languages extensions, Haskell behaves different for this module according to these. data kinds Can be temporary deleted to see what happens:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;#cb10-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;/home/jappie/projects/haskell/awesome-project-name/src/Lib.hs:14:16:&lt;/span&gt; error:&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;#cb10-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ex&quot;&gt;Illegal&lt;/span&gt; type: ‘&lt;span class=&quot;st&quot;&gt;&amp;quot;users&amp;quot;&lt;/span&gt;’ Perhaps you intended to use DataKinds&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;#cb10-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-4&quot;&gt;&lt;a href=&quot;#cb10-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;14&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;type&lt;/span&gt; UserAPI = &lt;span class=&quot;st&quot;&gt;&amp;quot;users&amp;quot;&lt;/span&gt; :&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; Get &lt;span class=&quot;st&quot;&gt;&amp;#39;[JSON] [User]&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-5&quot;&gt;&lt;a href=&quot;#cb10-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;   |                ^^^^^^^&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-6&quot;&gt;&lt;a href=&quot;#cb10-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-7&quot;&gt;&lt;a href=&quot;#cb10-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;/home/jappie/projects/haskell/awesome-project-name/src/Lib.hs:14:31: error:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-8&quot;&gt;&lt;a href=&quot;#cb10-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;    Illegal type: ‘&amp;#39;&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;]&lt;/span&gt;’ Perhaps you intended to use DataKinds&lt;/span&gt;
&lt;span id=&quot;cb10-9&quot;&gt;&lt;a href=&quot;#cb10-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-10&quot;&gt;&lt;a href=&quot;#cb10-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;14&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;type&lt;/span&gt; UserAPI = &lt;span class=&quot;st&quot;&gt;&amp;quot;users&amp;quot;&lt;/span&gt; :&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; Get &lt;span class=&quot;st&quot;&gt;&amp;#39;[JSON] [User]&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-11&quot;&gt;&lt;a href=&quot;#cb10-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;   |                               ^^^^^^^&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Data kinds is needed to insert data into a type. A string being data in this case, it is unclear what &lt;code&gt;&apos;[JSON]&lt;/code&gt; is, probably also something data. Temporary breaking a program to see what GHC will say is an effective way of learning more about Haskell.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;TypeOperators&lt;/code&gt; is disabled, GHC says it doesn’t like &lt;code&gt;:&amp;gt;&lt;/code&gt; in the &lt;code&gt;UserAPI&lt;/code&gt; line. Apparently &lt;code&gt;:&amp;gt;&lt;/code&gt; is a type operator. Apparently types can have operators.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;DeriveGeneric&lt;/code&gt; is disabled, GHC says it needs to derive &lt;a href=&quot;https://wiki.haskell.org/GHC.Generics&quot;&gt;generic&lt;/a&gt; in the data definition of User. Generic is required for serialization (in our case JSON conversion).&lt;/p&gt;
&lt;h2 id=&quot;modules&quot;&gt;Modules&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb11&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb11-1&quot;&gt;&lt;a href=&quot;#cb11-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lib&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-2&quot;&gt;&lt;a href=&quot;#cb11-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( webAppEntry&lt;/span&gt;
&lt;span id=&quot;cb11-3&quot;&gt;&lt;a href=&quot;#cb11-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-4&quot;&gt;&lt;a href=&quot;#cb11-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-5&quot;&gt;&lt;a href=&quot;#cb11-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Servant&lt;/span&gt;(serve, &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt;(..), &lt;span class=&quot;dt&quot;&gt;Server&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Get&lt;/span&gt;, (:&amp;gt;))&lt;/span&gt;
&lt;span id=&quot;cb11-6&quot;&gt;&lt;a href=&quot;#cb11-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Aeson&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb11-7&quot;&gt;&lt;a href=&quot;#cb11-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;GHC.Generics&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb11-8&quot;&gt;&lt;a href=&quot;#cb11-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Network.Wai&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;Application&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb11-9&quot;&gt;&lt;a href=&quot;#cb11-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Network.Wai.Handler.Warp&lt;/span&gt;(run)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Moving onward, there is the module definition that stack generated, modules are just namespaces, or similar to python modules. Nothing really special about those. Then there are many imports which pull functions into the module namespace.&lt;/p&gt;
&lt;h2 id=&quot;type-level-rest-api&quot;&gt;Type level REST API&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;#cb12-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserAPI&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;users&amp;quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Get&lt;/span&gt; &amp;#39;[&lt;span class=&quot;dt&quot;&gt;JSON&lt;/span&gt;] [&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This line defines the UserAPI type, which will serve as the REST endpoint. The image at the beginning of the post was about this line. Perhaps reading it as a sentence will give us some insight, without worrying about how it fits together: It’s a Get request, mounted below &lt;code&gt;/user&lt;/code&gt;, returning something JSON and of shape/type User. Conveniently what a &lt;code&gt;User&lt;/code&gt; is will be discussed in the next section.&lt;/p&gt;
&lt;h2 id=&quot;domain-data&quot;&gt;Domain data&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb13&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb13-1&quot;&gt;&lt;a href=&quot;#cb13-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-2&quot;&gt;&lt;a href=&quot;#cb13-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; name ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-3&quot;&gt;&lt;a href=&quot;#cb13-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; email ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-4&quot;&gt;&lt;a href=&quot;#cb13-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  } &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb13-5&quot;&gt;&lt;a href=&quot;#cb13-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-6&quot;&gt;&lt;a href=&quot;#cb13-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;User is just a data structure consisting of two strings: Email and name. This declaration method is called &lt;a href=&quot;http://learnyouahaskell.com/making-our-own-types-and-typeclasses#record-syntax&quot;&gt;record syntax&lt;/a&gt;. This data structure derives &lt;a href=&quot;https://hackage.haskell.org/package/base-4.9.1.0/docs/Text-Show.html&quot;&gt;Show&lt;/a&gt;, &lt;a href=&quot;http://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Eq.html&quot;&gt;Eq&lt;/a&gt; and Generic. Deriving means that GHC will generate function implementations for this data structure. If one calls &lt;code&gt;show&lt;/code&gt; on a User, it will know what to do (show is toString in Haskell). &lt;code&gt;instance ToJSON User&lt;/code&gt; allows the User to be converted to JSON (implementation is provided by generic).&lt;/p&gt;
&lt;h2 id=&quot;functions&quot;&gt;Functions&lt;/h2&gt;
&lt;p&gt;Done with data, time for code!&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb14-1&quot;&gt;&lt;a href=&quot;#cb14-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;users ::&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Specifies a function that will always return a list of Users. There are no arguments to this function. It can be assumed the list is always the same. This is how immutable constants are specified.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb15&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb15-1&quot;&gt;&lt;a href=&quot;#cb15-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;users &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-2&quot;&gt;&lt;a href=&quot;#cb15-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  [ &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Isaac Newton&amp;quot;&lt;/span&gt;    &lt;span class=&quot;st&quot;&gt;&amp;quot;isaac@newton.co.uk&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-3&quot;&gt;&lt;a href=&quot;#cb15-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  , &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Albert Einstein&amp;quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;ae@mc2.org&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-4&quot;&gt;&lt;a href=&quot;#cb15-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is the implementation of the before defined function. There are apparently two users in this list, one Isaac, and another Einstein. Note that positional arguments are used to create the Users.&lt;/p&gt;
&lt;h2 id=&quot;servant-server&quot;&gt;Servant server&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb16&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb16-1&quot;&gt;&lt;a href=&quot;#cb16-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;server ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserAPI&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;server :: Server UserAPI&lt;/code&gt; says that there is something called a Server which has a UserAPI. A UserAPI is known, it is defined above. A &lt;a href=&quot;http://hackage.haskell.org/package/servant-server-0.14/docs/Servant-Server.html#t:Server&quot;&gt;&lt;code&gt;Server&lt;/code&gt;&lt;/a&gt; is defined in servant. The type signature is rather complicated: &lt;code&gt;type Server api = ServerT api Handler&lt;/code&gt;, looking at the definition of &lt;code&gt;ServerT&lt;/code&gt; introduces a lot of complexity: &lt;code&gt;type ServerT api (m :: * -&amp;gt; *) :: *&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There are some clues that can be derived (such as that &lt;code&gt;m&lt;/code&gt;), but it’s not that important to make something work. Therefore this guide ignores it. Note that ignoring scary looking things is an important Haskell technique. If one is interested, help can be found &lt;a href=&quot;https://groups.google.com/forum/#!forum/haskell-servant&quot;&gt;here&lt;/a&gt;, just in case ❤.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb17&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb17-1&quot;&gt;&lt;a href=&quot;#cb17-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;server &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; users&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The implementation is very simple however. The reader should be cautious, to think that return is a keyword. It’s a function. What both return does is wrap a value into a container. For example an element can be wrapped in a list: &lt;code&gt;return 2 == [2]&lt;/code&gt;. That’s all one needs to know for now (the interested reader may look at &lt;a href=&quot;https://wiki.haskell.org/Monad#Monad_class&quot;&gt;monads&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id=&quot;proxy&quot;&gt;Proxy&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb18&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb18-1&quot;&gt;&lt;a href=&quot;#cb18-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;userAPI ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserAPI&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-2&quot;&gt;&lt;a href=&quot;#cb18-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;userAPI &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is just some type &lt;a href=&quot;http://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Proxy.html&quot;&gt;level magic&lt;/a&gt;. Library author needed type information for a function, but they didn’t need a value. Proxy does that. It’s useful if you store data at type level, for example with the datakinds language extension, which was seen earlier.&lt;/p&gt;
&lt;h2 id=&quot;application&quot;&gt;Application&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb19&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb19-1&quot;&gt;&lt;a href=&quot;#cb19-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;app ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Application&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-2&quot;&gt;&lt;a href=&quot;#cb19-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;app &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; serve userAPI server&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This combines the proxy and server. A serve function takes a Proxi API, Server API and returns an application. If type Application is inspected one can appreciate what serve does for us better:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb20&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb20-1&quot;&gt;&lt;a href=&quot;#cb20-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Application&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Request&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Response&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ResponseReceived&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ResponseReceived&lt;/span&gt; &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The arrows indicate function arguments. An application receives a request, then a callback which expects a &lt;code&gt;Response&lt;/code&gt; to produce an IO action which gives the result &lt;code&gt;ResponseReceived&lt;/code&gt;. However to return this function must also return a type &lt;code&gt;ResponseReceived&lt;/code&gt; wrapped in IO. It may be the case that the only way to obtain this response received is to call that callback. The freedom to do whatever one wants is meanwhile granted with the IO return type. To compile that &lt;code&gt;ResponseReceived&lt;/code&gt; has to be obtained however.&lt;/p&gt;
&lt;h2 id=&quot;running-it&quot;&gt;Running it!&lt;/h2&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb21&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb21-1&quot;&gt;&lt;a href=&quot;#cb21-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;webAppEntry ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb21-2&quot;&gt;&lt;a href=&quot;#cb21-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;webAppEntry &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; run &lt;span class=&quot;dv&quot;&gt;6868&lt;/span&gt; app&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Our initial function! Rather than saying hello world the app is ran on port 6868 (best port). Now build and run it in one terminal, and in another curl it:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb22&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb22-1&quot;&gt;&lt;a href=&quot;#cb22-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;stack&lt;/span&gt; build &lt;span class=&quot;kw&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;ex&quot;&gt;stack&lt;/span&gt; exec awesome-project-name-exe &lt;span class=&quot;kw&quot;&gt;&amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-2&quot;&gt;&lt;a href=&quot;#cb22-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;curl&lt;/span&gt; localhost:6868/users&lt;/span&gt;
&lt;span id=&quot;cb22-3&quot;&gt;&lt;a href=&quot;#cb22-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-4&quot;&gt;&lt;a href=&quot;#cb22-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;ex&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;isaac@newton.co.uk&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;Isaac Newton&amp;quot;&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;ex&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;ae@mc2.org&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;Albert Einstein&amp;quot;&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;ex&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure&gt;
&lt;img src=&quot;./images/2018/good-job.svg&quot; alt=&quot;Good job!&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Good job!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1 id=&quot;in-conclusion&quot;&gt;In conclusion&lt;/h1&gt;
&lt;p&gt;A lot of concepts have been treated within this blog post while also moving towards something productive. The reader can now start a new project and add arbitrary dependencies. He knows what language extensions are and how to see them in use. Type level magic has been encountered, and wisely was ignored. In future this post will build on top of this work to extend the API and do something with something within the handlers. However this post has grown to big already.&lt;/p&gt;
&lt;p&gt;The complete code can be found &lt;a href=&quot;https://github.com/jappeace/awesome-project-name/tree/simple-servent-setup&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Elm on fire! Shaders in elm</title>
    <link href="https://jappieklooster.nl/elm-on-fire-shaders-in-elm.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2018-06-23:/elm-on-fire-shaders-in-elm.html</id>
    <published>2018-06-23T12:00:00Z</published>
    <updated>2018-06-23T12:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="technique"/>
    <summary type="html">&lt;figure&gt;
&lt;img src=&quot;/images/2018/elm-fire.svg&quot; alt=&quot;Elm on fire&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Elm on fire&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Shaders have long been on the list of possible subject to study for Jappie. The potential of both creating &lt;a href=&quot;https://www.vertexshaderart.com/&quot;&gt;beautiful art&lt;/a&gt; as well as doing parallel processing seem incredible valuable capabilities to have. This post comments on the effort of porting a &lt;a href=&quot;https://github.com/ethanhjennings/webgl-fire-particles&quot;&gt;JavaScript WebGL fire&lt;/a&gt; to an&lt;/p&gt;</summary>
    <content type="html">&lt;figure&gt;
&lt;img src=&quot;/images/2018/elm-fire.svg&quot; alt=&quot;Elm on fire&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Elm on fire&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Shaders have long been on the list of possible subject to study for Jappie. The potential of both creating &lt;a href=&quot;https://www.vertexshaderart.com/&quot;&gt;beautiful art&lt;/a&gt; as well as doing parallel processing seem incredible valuable capabilities to have. This post comments on the effort of porting a &lt;a href=&quot;https://github.com/ethanhjennings/webgl-fire-particles&quot;&gt;JavaScript WebGL fire&lt;/a&gt; to an &lt;a href=&quot;https://github.com/jappeace/elmgl-fire&quot;&gt;elm implementation&lt;/a&gt;. Elm was chosen as target language because it is opinionated, easy and type safe. In this post we explore how to get started in elm with shaders, and then move on trying to port the fire project, finally performance is increased as much as possible.&lt;/p&gt;
&lt;h1 id=&quot;in-the-beginning-there-was-nothing.&quot;&gt;In the beginning there was nothing.&lt;/h1&gt;
&lt;p&gt;There are some &lt;a href=&quot;https://github.com/elm-community/webgl/tree/master/examples&quot;&gt;example shader&lt;/a&gt; setups for elm. The `crate’ was &lt;a href=&quot;https://github.com/jappeace/elmgl-fire/commit/fb735158f328789a7c30ae4088b8cffcc4be1fd2&quot;&gt;copied over&lt;/a&gt; resulting into having a fully 3d crate! This is not exactly the output desired, a crate is not a fire (obviously), but now there is a skeleton for the &lt;a href=&quot;https://guide.elm-lang.org/architecture/&quot;&gt;elm architecture&lt;/a&gt; and some example shaders to play with.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2018/crate.jpg&quot; alt=&quot;A crate in gl&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;A crate in gl&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;From here on there are two possible paths to continue, one can try and completely understand what the shaders do and how they work, or one can just copy over the shader code from the &lt;a href=&quot;https://github.com/ethanhjennings/webgl-fire-particles&quot;&gt;JavaScript&lt;/a&gt; project and see if we can make that work. Although &lt;a href=&quot;https://github.com/jappeace/elmgl-fire/commit/96f3dd293ad72f8b199d7958500f0f14ea2ed013&quot;&gt;initial work&lt;/a&gt; was started on the former approach, the latter approach won out because the topic of ‘shader’ is just too large. There is a lot of math involved. Although this is an exercise of exploration and learning, trying to understand it all is a massive scope creep.&lt;/p&gt;
&lt;h1 id=&quot;unbreak-rendering&quot;&gt;Unbreak rendering&lt;/h1&gt;
&lt;p&gt;After copying over the shader logic from the fire project, everything broke. This was not surprising as the crate project was 3d, whereas the fire project was 2d. Luckily Elm has strongly typed input for the shaders. Therefore solving these mismatches was relatively easy. We could just follow the compile errors. After &lt;a href=&quot;https://github.com/jappeace/elmgl-fire/commit/668f714294b4423ae51e8857bf7d9e8dafa4ba8c&quot;&gt;that&lt;/a&gt;, the example program was essentially gutted, only the basic architecture and API calls were left in tact. Elm forces this architecture upon us, there is no choice in this. The result of this effort is shown below.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2018/gl-something.jpg&quot; alt=&quot;Something in gl&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Something in gl&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;It does not look like much of anything, however, this is counted as progress. Not having a blank screen is good. The next thing to do was fixing the colors. This happened by porting the &lt;a href=&quot;https://github.com/jappeace/elmgl-fire/commit/dbe4c308dcc24f0af8ea6b8f85991c1d83354002&quot;&gt;hue code&lt;/a&gt;, there was no elm implementation for this particular kind of Hue representation. Because a white background and the hue produces light blue, we added a &lt;a href=&quot;https://github.com/jappeace/elmgl-fire/commit/dbe4c308dcc24f0af8ea6b8f85991c1d83354002#diff-3e16369f543b857a1fea048cf77b7315R120&quot;&gt;black background&lt;/a&gt; which mixes into an orange. Now we had the right color, however transparency was also broken. Transparency was quite interesting because my initial fix involved changing the shader. However the the &lt;a href=&quot;https://github.com/jappeace/elmgl-fire/commit/dbe4c308dcc24f0af8ea6b8f85991c1d83354002#diff-3e16369f543b857a1fea048cf77b7315R136&quot;&gt;right (API) option&lt;/a&gt; was eventually found &lt;a href=&quot;https://github.com/jappeace/elmgl-fire/commit/bc9f5d3eecbdc47c0ef0685a005c2af03e1ccd5c&quot;&gt;that solved this issue&lt;/a&gt;. With all of this in place we get a single circle with the right color!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2018/gl-reddot.jpg&quot; alt=&quot;Single circle!&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Single circle!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Baby steps. Graphics take time.&lt;/p&gt;
&lt;h1 id=&quot;random-spheres&quot;&gt;Random spheres&lt;/h1&gt;
&lt;p&gt;This is not impressive at all. However, in life one may find that arity changes everything. A single dot on it’s own is just a single dot, but if we randomly place it all over the screen we get something nice to look at (live &lt;a href=&quot;/raw-html/2018/random-spheres.html&quot;&gt;here&lt;/a&gt;):&lt;/p&gt;
&lt;video controls loop video controls autoplay&gt;
&lt;source src=&quot;/images/2018/spheres.webm&quot; type=&quot;video/webm&quot;&gt;
&lt;p&gt;Your browser does not support the video tag. &lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Aside from random creation this doesn’t bring us much closer to the goal of fire. However some more work was done on it because Jappie thought it looked beautiful. Performance was increased by converting a particle immediately into it’s WebGL representation.&lt;/p&gt;
&lt;h1 id=&quot;movement&quot;&gt;Movement&lt;/h1&gt;
&lt;p&gt;To do movement we dropped some changes from the random sphere case. The idea of not doing an update loop at all was temporary put aside, because using an update loop is closer to the JavaScript original. Keeping it would make porting easier.&lt;/p&gt;
&lt;p&gt;Doing movement is simply adding velocity times time to position every frame. That’s it. The simplex noise part of the JavaScript code was also implemented for variation in movement.&lt;/p&gt;
&lt;p&gt;It turns out however that the result is somewhat unimpressive. Yes it looks like fire, but after about 20 seconds the memory is full, garbage collection kicks in and the program grinds to an halt. Here is an example (live &lt;a href=&quot;/raw-html/2018/slow-fire.html&quot;&gt;here&lt;/a&gt;, may grind your computer to a halt):&lt;/p&gt;
&lt;video controls loop video controls autoplay&gt;
&lt;source src=&quot;/images/2018/slow-fire.webm&quot; type=&quot;video/webm&quot;&gt;
&lt;p&gt;Your browser does not support the video tag. &lt;/video&gt;&lt;/p&gt;
&lt;h2 id=&quot;speed&quot;&gt;Speed&lt;/h2&gt;
&lt;p&gt;The problem is that aside from creating particles and sending them to a GPU, All existing particles must every cycle be updated with the new location. We may observer however that the path of the particles after creation is entirely deterministic. Why don’t we let the shaders do this? The idea being that we create particles with an initial position, timestamp and velocity. Then let the shaders calculate the position for whatever the current timestamp is.&lt;/p&gt;
&lt;p&gt;When trying to implement this, it was found out that the elm gl API was used in a inefficient way. The realization came that using an entity per quad doesn’t allow us to share the uniform across all quads. These entities are analogues to WebGL ‘programs’&lt;/p&gt;
&lt;p&gt;The architecture was redesigned to take into account multiple particles per elm entity. Rather than tracking lists of entities, lists of tuples of vertices are now being tracked: &lt;code&gt;List (Vertex, Vertex, Vertex)&lt;/code&gt;. It would’ve been preferable to use &lt;code&gt;Mesh Vertex&lt;/code&gt; as type, but this type does not support appending in the elm shader API.&lt;/p&gt;
&lt;p&gt;This approach seemed to work much better, in fact this is probably how one should use this API. It was possible to render 500 particles now and the computer didn’t lock up (at all):&lt;/p&gt;
&lt;p&gt;live &lt;a href=&quot;/raw-html/2018/fast-fire.html&quot;&gt;here&lt;/a&gt; &lt;video controls loop video controls autoplay&gt; &lt;source src=&quot;/images/2018/fast-fire.webm&quot; type=&quot;video/webm&quot;&gt; Your browser does not support the video tag. &lt;/video&gt;&lt;/p&gt;
&lt;p&gt;It’s still not very good, as the original JavaScript implementation was able to do up to 3000 particles per seconds quite comfortably (with a much better frame rate)… There is not a lot of things done in the this implementation on the CPU side, and still the CPU intense JavaScript implementation is faster. Perhaps this is just a limit of using elm.&lt;/p&gt;
&lt;h2 id=&quot;more-speed&quot;&gt;More speed?&lt;/h2&gt;
&lt;p&gt;After thinking about the problem for some time another idea came to mind. To increase speed, the amount of information send to the GL pipeline can be reduced. Every frame sends this Mesh collection to the GPU trough a buffer, if this buffer can be decreased in size, speed would increase. It would also lighten the load on garbage collection, as less objects need to be created. The suspicion is that elm is slow just because of garbage collection. We can do this rather trivially by representing each particle as a single vertex, with a position and size. Then we just use a shader to reconstruct the vertices into quads (squares). The vertex shader would move the vertex first, then another (unkown) shader would do reconstruction, then the fragment shader would do drawing. Easy as π.&lt;/p&gt;
&lt;p&gt;Stack overflow &lt;a href=&quot;https://stackoverflow.com/questions/5821152/opengl-add-vertices-with-vertex-shader&quot;&gt;suggests&lt;/a&gt; that we can use a geometry shader for this. Unfortunately the elm GL API doesn’t support this, it only has a slot for vertex, and fragment shader in the &lt;a href=&quot;http://package.elm-lang.org/packages/elm-community/webgl/2.0.5/WebGL#entity&quot;&gt;entity function&lt;/a&gt;. Jappie briefly got excited about adding this shader type to the elm API, however he discovered that WebGL doesn’t support this type of &lt;a href=&quot;https://stackoverflow.com/questions/8641119/webgl-geometry-shader-equivalent&quot;&gt;shader at all&lt;/a&gt;. From this point it’s unclear how to increase speed. Changing WebGL itself is borderline impossible (it would take at least years).&lt;/p&gt;
&lt;h1 id=&quot;in-conclusion&quot;&gt;In conclusion&lt;/h1&gt;
&lt;p&gt;Upon discovery of the WebGL API for elm Jappie was quite excited about using that. However after using it, and finding the rather large performance difference the excitement has been tempered. Still a lot was learned from doing this project, elm is a good entry point for graphics development, type-safety makes the complexity quite manageable. In fact the idea for using geometry shaders would not had been realized at all in a faster language.&lt;/p&gt;
&lt;p&gt;However in future a faster language will be used. Not being able to get everything from a machine is quite frustrating. This therefore will exclude any use of WebGL. A major drive for using WebGL in the first place was to share the result online, however this reasoning is quite flawed in that a video of the result can just be made. After all we don’t even include the live results here because of concern that it will freeze the readers’ computer.&lt;/p&gt;
&lt;p&gt;To all who are interested in graphics elm is recommended to start with. Especially if they are already familiar with elm or the react/redux architecture. Type safety on shader level is really nice, especially when you do things wrong structurally and the compiler exactly tells you where you need to repair things (as happened during this project with the entities). The price one pays is execution speed in return for development speed.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Fun with stack: Haskell dependency management</title>
    <link href="https://jappieklooster.nl/fun-with-stack-haskell-dependency-management.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2018-05-13:/fun-with-stack-haskell-dependency-management.html</id>
    <published>2018-05-13T16:00:00Z</published>
    <updated>2018-05-13T16:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;figure&gt;
&lt;img src=&quot;/images/2018/haskell-stack-logo.svg&quot; alt=&quot;Haskel stack logo&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Haskel stack logo&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Working at Daisee, Jappie uses a lot of Haskell programming. Although Haskell is obviously as amazing as the &lt;a href=&quot;https://www.reddit.com/r/haskell/comments/zpff3/larry_wall_you_should_probably_know_about_it/&quot;&gt;stereotype asserts&lt;/a&gt;, the tooling can be a bit challenging. In this blogpost we explore these challenges.&lt;/p&gt;
&lt;p&gt;One’s understanding start with the fact that there is not one unified&lt;/p&gt;</summary>
    <content type="html">&lt;figure&gt;
&lt;img src=&quot;/images/2018/haskell-stack-logo.svg&quot; alt=&quot;Haskel stack logo&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Haskel stack logo&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Working at Daisee, Jappie uses a lot of Haskell programming. Although Haskell is obviously as amazing as the &lt;a href=&quot;https://www.reddit.com/r/haskell/comments/zpff3/larry_wall_you_should_probably_know_about_it/&quot;&gt;stereotype asserts&lt;/a&gt;, the tooling can be a bit challenging. In this blogpost we explore these challenges.&lt;/p&gt;
&lt;p&gt;One’s understanding start with the fact that there is not one unified Haskell package manager. Well there is, but only experts use &lt;a href=&quot;https://www.haskell.org/cabal/&quot;&gt;cabal&lt;/a&gt; directly. The issue is that often dependencies don’t quite match from the &lt;a href=&quot;https://hackage.haskell.org/&quot;&gt;Hackage&lt;/a&gt; repository, which cabal uses as repository. Loose version bounds within cabal configurations, cause one developer to develop against version &lt;code&gt;1.1&lt;/code&gt; and another against version &lt;code&gt;1.2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is were &lt;a href=&quot;https://www.stackage.org/&quot;&gt;stack&lt;/a&gt; stepped in. Stack guarantees that at some point in time all the provided packages in their repository will build together. They do this trough package curation and providing reproducible builds at least for &lt;a href=&quot;https://github.com/commercialhaskell/stack/blob/master/doc/GUIDE.md#what-makes-stack-special&quot;&gt;Haskell packages&lt;/a&gt;. This is hosted on their alternative to &lt;a href=&quot;https://hackage.haskell.org/&quot;&gt;Hackage&lt;/a&gt;, called &lt;a href=&quot;https://www.stackage.org/&quot;&gt;Stackage&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Because of curation and being more restrictive, the stackage repository doesn’t host as much software as hackage does. In certain cases we may still need to configure stack in such a way that it pulls in a package or two from hackage.&lt;/p&gt;
&lt;h1 id=&quot;system-dependencies&quot;&gt;System dependencies&lt;/h1&gt;
&lt;p&gt;Haskell is not an operating system. There is no Haskell Linux kernel or Haskell std lib. Therefore many Haskell libraries are dependent upon C code libraries. Stack does not include interaction with these system libraries as part of it’s reproducible build contract.&lt;/p&gt;
&lt;p&gt;The user experiences this once stack starts requesting ‘devel’ packages, for example: Stack will request ‘ssl’ headers, and recommends the user to install a devel system package from his distribution package manager. It is up to the user to find the name of this system package for his respective distribution, in case of fedora it’s: “openssl-devel”, and in case of Ubuntu it’s “libssl-dev”. But gentoo wouldn’t even have devel packages, all packages in case of gentoo are devel packages.&lt;/p&gt;
&lt;h2 id=&quot;enter-nix&quot;&gt;Enter nix&lt;/h2&gt;
&lt;p&gt;Nix is also a package manager like stack and cabal are, however, it’s not focused on any specific language. Nix is about reproducible builds, eg guaranteeing some build on a developer machine is exactly the same as on the user machine.&lt;/p&gt;
&lt;p&gt;A developer may for example have had the ssl library installed globally, but forgot to mark it as a dependency in his software package. A build tool would happily build that on his machine, but now when a user downloads this code and tries to build the package it will fail. Nix &lt;a href=&quot;https://nixos.org/~eelco/pubs/phd-thesis.pdf&quot;&gt;solves this&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In principle nix is completely independent from the Haskell ecosystem. Build around this package manager is even an entire &lt;a href=&quot;https://nixos.org/&quot;&gt;distribution&lt;/a&gt;. But because it provides system dependencies &lt;em&gt;and&lt;/em&gt; haskell dependency management, and does so in a reproducible manner at system level, it has become very popular among the correctness loving Haskell programers.&lt;/p&gt;
&lt;p&gt;However it may be pointed out that although what nix does is impressive compared to stack it’s harder to use. The langauge nix langauge is peculiar, for example it has both a &lt;code&gt;;&lt;/code&gt;, and being reduced to a single expression. It has no type system but does full correctness checking before exucting. But it has a massive repository of &lt;a href=&quot;https://github.com/NixOS/nixpkgs&quot;&gt;examples&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;stack-and-nix&quot;&gt;Stack and nix&lt;/h2&gt;
&lt;p&gt;Stack provides the ability to specify system dependencies trough nix. Which is very useful as you now can let any developer regardless of Linux distribution, get on board with your stack project, without having to find out which specific system packages need to be installed. Is this combination the solution? Easy to use and being fully reproducible? Alas no this setup also has issues.&lt;/p&gt;
&lt;p&gt;It has an opt in for the isolated builds nix provides, so stack would first look if a package is specified in the nix configuration, if not it would fall back on system libraries. This is rather strange, because you enable the plugin for reproducible builds, but the default behavior is to look for system libraries (eg be not reproducible). There is an opt out for this behavior (&lt;code&gt;pure:true&lt;/code&gt;), but it seems more sensible to make this an opt in.&lt;/p&gt;
&lt;p&gt;The reason why this behavior is undesired is because if one programmer starts using &lt;code&gt;http-client-openssl&lt;/code&gt;, and happens to have &lt;code&gt;openssl-devel&lt;/code&gt; installed on his system, then his colleague try to build the project, his build will fail. If &lt;code&gt;pure:true&lt;/code&gt; was enabled the first developer would’ve noticed the issue and added it into the nix configuration.&lt;/p&gt;
&lt;p&gt;However the way stack tells the user about the missing dependency is also peculiar. In case of the pure configuration, if stack can’t find the library, it will ask the user to install the dependency on his system. Which is of course pointless because one needs to add it to the nix configuration &lt;img src=&quot;/images/2018/stack-error.jpg&quot; alt=&quot;Stack error message&quot; /&gt; Although the error message was intended to be helpful, in this particular case it ends up sending the user in the wrong direction.&lt;/p&gt;
&lt;h1 id=&quot;git-and-stack&quot;&gt;Git and stack&lt;/h1&gt;
&lt;p&gt;Stack’s power lies in that it makes it easy to do the common things. For example creating a library for github is trivial. Stack helps by allowing users to specify a ‘github’ field in the &lt;code&gt;package.yaml&lt;/code&gt; file, which will generate an url to both the source and the issue tracker on github.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt;                voicebase&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt;             &lt;/span&gt;&lt;span class=&quot;fl&quot;&gt;0.1.0.0&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;license&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt;             BSD3&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;Jappie Klooster&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;#cb1-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;maintainer&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;jappie.klooster@daisee.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;#cb1-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;copyright&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt;           &lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;Daisee&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;#cb1-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt;              blah/blah&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now although github is extremely popular in opensource it’s of course not the only choice, One may put it on a different host, such as &lt;a href=&quot;https://bitbucket.org/daisee/voicebase/src/master/&quot;&gt;bitbucket&lt;/a&gt;, or host their own source code with &lt;a href=&quot;https://gitlab.com&quot;&gt;gitlab&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There is no doubt that stack supports specifying an alternative, however it is unclear how to replace the github field properly with alternatives. The assumption was that the &lt;code&gt;gihtub&lt;/code&gt; field was just a shorthand to fill in some other fields. It is hard to find what it does because it’s an odly specific question, but it &lt;a href=&quot;https://stackoverflow.com/questions/40332040/what-goes-in-a-stack-package-yaml-file?utm_medium=organic&amp;amp;utm_source=google_rich_qa&amp;amp;utm_campaign=google_rich_qa&quot;&gt;turns out&lt;/a&gt; that &lt;a href=&quot;https://github.com/sol/hpack&quot;&gt;hpack&lt;/a&gt; is used to parse the &lt;code&gt;package.yaml&lt;/code&gt; file. Perhaps the &lt;code&gt;git&lt;/code&gt; field is used to replace &lt;code&gt;github&lt;/code&gt;? It is unclear. It’s also ironic in that we can immediatly observe the difference strong types make in documentation ability, this yaml file is not strongly typed.&lt;/p&gt;
&lt;h2 id=&quot;commit-dependencies&quot;&gt;Commit dependencies&lt;/h2&gt;
&lt;p&gt;In certain situations one may need to change a library. The typical way of doing this is to make a github fork, and then specify in the dependency manager, that a specific (git) url needs to be used on a specific commit hash. For example: If one tries to get the &lt;code&gt;56e833&lt;/code&gt; commit from the &lt;a href=&quot;https://bitbucket.org/daisee/voicebase/src/master/&quot;&gt;voicebase library&lt;/a&gt;, you should record the hash and url somewhere.&lt;/p&gt;
&lt;p&gt;If we google for the query &lt;code&gt;stack.yaml git dependency&lt;/code&gt;, you just need to know that you configure this in &lt;code&gt;stack.yaml&lt;/code&gt;, which is completely unrelated to &lt;code&gt;package.yaml&lt;/code&gt; google points you to an outdated doc page which fails to work. A helping &lt;a href=&quot;https://stackoverflow.com/questions/43789271/stack-yaml-not-pulling-in-dependency-from-github?utm_medium=organic&amp;amp;utm_source=google_rich_qa&amp;amp;utm_campaign=google_rich_qa&quot;&gt;stackoverflow&lt;/a&gt; gives the reason why it doesn’t work, the syntax recently has changed and Google hasn’t updated yet. One can hardly blame stacks maintainers for this of course. But it still impacts a users’ experience.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2018/stack-old-docs.jpg&quot; alt=&quot;Outdated docs&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Outdated docs&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Dependency management in Haskell is complicated. Even if one is able to become productive in the langauge, any of the problems described here could still make it difficult enough for them to give up on the system they want to build. Learning about functors and applicative is fun, learning what specific syntax to use to make stack pull in a git repository is not.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Reddit poster plugin for pelican</title>
    <link href="https://jappieklooster.nl/reddit-poster-plugin-for-pelican.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2018-05-07:/reddit-poster-plugin-for-pelican.html</id>
    <published>2018-05-07T09:00:00Z</published>
    <updated>2018-05-07T09:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;Yesterday the &lt;a href=&quot;https://github.com/getpelican/pelican-plugins/pull/1026&quot;&gt;Reddit Poster&lt;/a&gt; plugin for &lt;a href=&quot;http://docs.getpelican.com/en/stable/&quot;&gt;pelican&lt;/a&gt; was finished. This is an initial step towards providing Reddit integration with pelican.&lt;/p&gt;
&lt;p&gt;What this plugin does is look a predefined list of subreddits names in &lt;a href=&quot;https://raw.githubusercontent.com/jappeace/jappeaceApplication/master/content/reddit-poster.md&quot;&gt;an article&lt;/a&gt;, then it posts the article to all those subreddits. Aside from the subreddits in&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Yesterday the &lt;a href=&quot;https://github.com/getpelican/pelican-plugins/pull/1026&quot;&gt;Reddit Poster&lt;/a&gt; plugin for &lt;a href=&quot;http://docs.getpelican.com/en/stable/&quot;&gt;pelican&lt;/a&gt; was finished. This is an initial step towards providing Reddit integration with pelican.&lt;/p&gt;
&lt;p&gt;What this plugin does is look a predefined list of subreddits names in &lt;a href=&quot;https://raw.githubusercontent.com/jappeace/jappeaceApplication/master/content/reddit-poster.md&quot;&gt;an article&lt;/a&gt;, then it posts the article to all those subreddits. Aside from the subreddits in the list, there is also a ‘collection’ subreddit where all articles posted too.&lt;/p&gt;
&lt;p&gt;Another goal in the future may be the ability to fetch comments from reddit at compile time and display them below posts. However the decision was reached to reduce the scope of this project to just posting first, as there was not enough time available to make fetching work. It is hoped however that many people now will start reacting to these posts so that it may be useful to implement this ability too. That will however be done in a separate plugin.&lt;/p&gt;
&lt;p&gt;This project has been lingering in Jappie’s TODO list for years now. It is a great relief to finally make some progress in it. To advertise this website now the only thing that needs to be done is specifying the list of subs in the relevant article.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Starting at Daisee</title>
    <link href="https://jappieklooster.nl/starting-at-daisee.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2018-04-11:/starting-at-daisee.html</id>
    <published>2018-04-11T20:30:00Z</published>
    <updated>2018-04-11T20:30:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;p&gt;Recently quite a few changes have happened within Jappies’ life. First of all, he is no longer at &lt;a href=&quot;https://www.openlearning.com/&quot;&gt;OpenLearning&lt;/a&gt;. This relationship ended at the end of February. March was used for job searching. To help with this a proper &lt;a href=&quot;https://jappieklooster.nl/pages/portfolio.html&quot;&gt;portfolio&lt;/a&gt; was constructed. Last week there were three interviews with&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Recently quite a few changes have happened within Jappies’ life. First of all, he is no longer at &lt;a href=&quot;https://www.openlearning.com/&quot;&gt;OpenLearning&lt;/a&gt;. This relationship ended at the end of February. March was used for job searching. To help with this a proper &lt;a href=&quot;https://jappieklooster.nl/pages/portfolio.html&quot;&gt;portfolio&lt;/a&gt; was constructed. Last week there were three interviews with Daisee, and Saturday Jappie accepted the offer.&lt;/p&gt;
&lt;h1 id=&quot;bio&quot;&gt;Bio&lt;/h1&gt;
&lt;p&gt;For this new job Jappie was asked to write a short bio, which he thought would be a nice addition to this blog post as it explains his current situation quite well:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Jappie joins &lt;a href=&quot;https://daisee.com&quot;&gt;Daisee&lt;/a&gt; as Software Engineer, he is quite excited about working with Haskell and practical AI.&lt;/p&gt;
&lt;p&gt;In his previous role Jappie was a Full stack developer at OpenLearning. Building various systems, from spam detection to remote code execution within containers. Before that he just graduated from his MSc in AI from Utrecht University, he chose to travel rather than taking up an offer for a PhD position&lt;br /&gt;
because he didn’t felt much for a career in academia. The decision for doing a masters in AI was made during his time in China where he did an internship for his bachelor degree in Software Engineering.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Arriving here on a `working holiday’, Jappie likes it here and hopes he can stay longer. The weather is better, the meetups are interesting, and it’s quite satisfying to build up a life starting from almost nothing. Jappie enjoys building things, from programming project to virtual kingdoms in computer games.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;expectations&quot;&gt;Expectations&lt;/h1&gt;
&lt;p&gt;Daisee and Jappie found each other at the functional programming meetup. They announced it as doing work with AI, and Jappie happens to be interested in both functional programming as well as AI.&lt;/p&gt;
&lt;p&gt;During the interview it was explained that initial tasks however were of a more practical nature. Such as devops and implementing a better UI. so there isn’t much AI work to begin with. However Jappie expects that after a while there would be more tasks in either of that.&lt;/p&gt;
&lt;h1 id=&quot;first-day&quot;&gt;First day&lt;/h1&gt;
&lt;p&gt;After finishing his first day Jappie looks back with satisfaction. The CTO takes a much more active role than at his previous company, which is pleasant because now it feels like there is direction. His colleagues seem nice too, all day people were coming over to introduce themselves to Jappie. His desk neighbor is also nice and very knowledge-able. Apparently a hardened Haskell veteran and a fellow Gentoo user/victim (rip Gentoo).&lt;/p&gt;
&lt;p&gt;Then there was the coffee machine. At his previous job the CEO didn’t like coffee, so didn’t invest in it. In the new job however there was a full blown espresso machine. This machine is both a blessing and a curse, it’s a blessing in that now one can drink all he desires, but a curse in that addiction will follow. Not to speak about the impact it has upon ones’ sleep cycle.&lt;/p&gt;
&lt;p&gt;Thinking about the introductions, some of his colleagues had very impressive track records indeed. For example, one of the founders apparently led a merger between two big companies. At the time it Jappie didn’t quite realize how difficult doing such a thing is. Jappie thinks it’s a good thing he’s surrounded by veterans. He can learn a lot from these people, just by being around them.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Flask, docker and the backend</title>
    <link href="https://jappieklooster.nl/flask-docker-and-the-backend.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2018-03-11:/flask-docker-and-the-backend.html</id>
    <published>2018-03-11T00:00:00Z</published>
    <updated>2018-03-11T00:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;Jappie Klooster is working with friends on a react native app. It was attempted to do this completely without server-side with help of Firebase. This post describes the thought process behind not using Firebase for &lt;em&gt;everything&lt;/em&gt;, and setting up a custom backend instead.&lt;/p&gt;
&lt;p&gt;The first major issue, for this&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Jappie Klooster is working with friends on a react native app. It was attempted to do this completely without server-side with help of Firebase. This post describes the thought process behind not using Firebase for &lt;em&gt;everything&lt;/em&gt;, and setting up a custom backend instead.&lt;/p&gt;
&lt;p&gt;The first major issue, for this use case specifically, is the type of database provided within Firebase. It’s a NoSQL database that promises to sync between all devices. They probably mean syncing lazily, it’s implied in the docs, but there is no definitive statement around that. NoSQL is the idea that &lt;a href=&quot;http://www.monitis.com/blog/cc-in-review-the-key-differences-between-sql-and-nosql-dbs/&quot;&gt;data doesn’t need relationships&lt;/a&gt;. For the core business logic of our app, we need relationships between data, and we need a lot of them. Technically one can represent these within NoSQL, but now you need to solve problems which most SQL databases have already done for you.&lt;/p&gt;
&lt;p&gt;Another &lt;em&gt;big&lt;/em&gt; disadvantage of Firebase is that it’s proprietary. Once a large chunk of the business logic, and data resides inside the Firebase ecosystem, it’s hard to get out. This means it’s relatively easy for the owner of the proprietary system, Google, to crank up the price. Neither Jappie nor his collaborators wanted to&lt;/p&gt;
&lt;h1 id=&quot;language-choice&quot;&gt;Language choice&lt;/h1&gt;
&lt;p&gt;The primary question imposed for deciding which language to use was “How fast do you want it?”. &lt;em&gt;Fast&lt;/em&gt;. Therefore a host of options was eliminated, such as Haskell and Rust. In fact because we wanted a pan-team familiar choice, only two real contenders were left. NodeJS and Python. The choice of Python was made because it is a much more simple language than JavaScript. Another advantage of choosing either for these languages would be that our editors are already setup to handle them.&lt;/p&gt;
&lt;h1 id=&quot;docker&quot;&gt;Docker&lt;/h1&gt;
&lt;p&gt;Many members of the team stressed the importance of containerization. Jappie, being the only one that had worked intimately with this technology was quite happy with this development. What was rather surprising was the suggestion that the team ought to run these containers by hand on rented VPS’es. Is docker not supposed to make orchestration more easy? Do there not exist many tools that build on top of docker to provide variances in orchestration? Such as docker-compose, docker swarm, appengine and Kubernetes? All these questions entered into Jappie’s mind, but he felt arguing in this case would be difficult wihtout an example. Once the team would start working with the containers they would see for themselves how easy orchestration is. The primary building block was in place anyway (docker), moving to another orchestration methodology will be easy.&lt;/p&gt;
&lt;p&gt;It was here that Jappie decided to pick up this task. He knew about docker from previous experience already, and his other major task had just finished. He started with a little hello world in python served through &lt;a href=&quot;http://flask.pocoo.org/&quot;&gt;flask&lt;/a&gt;. The he put this in a docker container by writing a &lt;code&gt;Dockerfile&lt;/code&gt;, and finally he wrote a little docker-compose script to attach an idle Postgres container which would be need later. All this was done in the space of about an hour or two. Setting up docker isn’t difficult. Then it was time for the next step, connecting flask to Postgres.&lt;/p&gt;
&lt;h1 id=&quot;flask&quot;&gt;Flask&lt;/h1&gt;
&lt;p&gt;Flask is a micro framework. It gives some Rest support, and that’s about it. They sometimes provide some glue scripts that connect some projects to other projects, but there is no main monolithic architecture behind it. In stark contrast to &lt;a href=&quot;https://www.djangoproject.com/&quot;&gt;Django&lt;/a&gt;, which has already done most things for you.&lt;/p&gt;
&lt;p&gt;This micro framework setup, gives the project a big advantage in that they can have independent versions, and gives the capability to swap out some projects for others quite easily. The big disadvantage, as Jappie encountered, is that its fairly challenging to get into. One may even say it’s hard to get started. The reason for this is that gluing the ORM to the framework has to be done by hand. This is of course because people may want to choose a NoSQL storage mechanism rather than an SQL. Jappie wanted to have an ORM to handle migrations and as a method of describing the model in.&lt;/p&gt;
&lt;p&gt;The thing that ended up working for Jappie was this &lt;a href=&quot;https://github.com/davidism/basic_flask&quot;&gt;bootstrapping script&lt;/a&gt; which was about 5 years old and of course outdated. But Jappie managed to get &lt;a href=&quot;https://github.com/jappeace/basic_flask&quot;&gt;it running&lt;/a&gt;, by googling errors, and stripping features. This should make it easier for future projects to start with flask in a docker environment. A pull request was made to merge it back into the original project.&lt;/p&gt;
&lt;h1 id=&quot;deploying&quot;&gt;Deploying&lt;/h1&gt;
&lt;p&gt;Once the docker-compose setup was completed considerations went out how to deploy this live. Being able to setup a live instance early has the advantage that the team can test the entire (rather complex) infrastructure. AppEngine was chosen as method of deployment as it could save in costs. AppEngine essentially allows client code to be shared across Kubernetes clusters (one assumes), making it cheaper for small apps to use as the overhead of running Kubernetes itself does not need to be taken in account.&lt;/p&gt;
&lt;p&gt;Since Jappie had never worked with AppEngine before he chose to do the &lt;a href=&quot;https://cloud.google.com/python/getting-started/hello-world&quot;&gt;hello world&lt;/a&gt; tutorial first. Note that he had to choose the flexible environment as the standard one only provides python 2.7, which at the time of writing has a bit over &lt;a href=&quot;https://pythonclock.org/&quot;&gt;two years&lt;/a&gt; left until deprecated. Using python 2.7 is therefore a really bad choice. Even though google &lt;a href=&quot;https://cloud.google.com/appengine/docs/the-appengine-environments&quot;&gt;says&lt;/a&gt; python 2.7 is the standard, Jappie urges his peers to take this claim with suspicion. Which the &lt;a href=&quot;https://wiki.python.org/moin/Python2orPython3&quot;&gt;python wiki&lt;/a&gt; backs up:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Python 2.x is legacy, Python 3.x is the present and future of the language&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After the hello world was successfully put online (in python 3 with the flexible environment), it was time to try setting up the entire system. For this a managed Postgres needed to be setup on Google Cloud and connected to AppEngine.&lt;/p&gt;
&lt;p&gt;Google however seems to favor more popular technologies, and the primary docs assume you want to use &lt;a href=&quot;https://cloud.google.com/python/getting-started/using-cloud-sql&quot;&gt;MySQL&lt;/a&gt;. Postgres was the preferred choice for the team however. It is more &lt;a href=&quot;https://www.quora.com/What-are-pros-and-cons-of-PostgreSQL-and-MySQL-With-respect-to-reliability-speed-scalability-and-features&quot;&gt;standard compliant and has better data types&lt;/a&gt;. An Uber post however claims there are some interesting advantages to &lt;a href=&quot;https://eng.uber.com/mysql-migration/&quot;&gt;MySQL&lt;/a&gt; if you manage the architecture yourself. This is done by google however in this use case, besides because an ORM is used, switching database technology is relatively easy.&lt;/p&gt;
&lt;p&gt;The search engine doesn’t show the docs for Postgres with flask in AppEngine. These docs were found in the &lt;a href=&quot;https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/appengine/flexible&quot;&gt;example project&lt;/a&gt;. The source file had a link to &lt;a href=&quot;https://cloud.google.com/appengine/docs/flexible/python/using-cloud-sql-postgres&quot;&gt;using postgres with AppEngine&lt;/a&gt;. To test if the Postgres instance was running this &lt;a href=&quot;https://cloud.google.com/sql/docs/postgres/connect-admin-proxy&quot;&gt;guide&lt;/a&gt; was used. Jappie was uncertain why a cloud proxy was recommended this much, in his memory he hadn’t set this up last time with a Django project. However with that in place one can create a &lt;a href=&quot;https://medium.com/@mohammedhammoud/postgresql-create-user-create-database-grant-privileges-access-aabb2507c0aa&quot;&gt;specialized user&lt;/a&gt; for manipulating the database (rather than the root Postgres account).&lt;/p&gt;
&lt;p&gt;Going trough those tutorials the useful commands were collected into a makefile. With this in place he had no longer need to refer to them and could just &lt;code&gt;cat&lt;/code&gt; the makefile to see how to deploy for example:&lt;/p&gt;
&lt;pre class=&quot;make&quot;&gt;&lt;code&gt;deploy:
    SQLALCHEMY_DATABASE_URI=postgresql+psycopg2://USER:PASWORD@/DB?host=localhost python ./manage.py db upgrade || (echo &amp;quot;make sure the proxy is running&amp;quot; &amp;amp;&amp;amp; false)
    gcloud app deploy

describe:
    gcloud sql instances describe DB_NAME

proxy:
    cloud_sql_proxy -instances=INSTANCE_PATH=tcp:5432

connect:
    echo &amp;quot;warning, requires you to setup the proxy in another terminal&amp;quot;
      # psql &amp;quot;host=127.0.0.1 sslmode=disable user=postgres&amp;quot;
    psql &amp;quot;host=127.0.0.1 sslmode=disable user=USER dbname=DB password=PASSWORD&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now any of the team could deploy with &lt;code&gt;make deploy&lt;/code&gt;. Note that the credentials where retracted out of security reasons.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;There is a lot involved to setting up a backend. It took about two days going from knowing almost nothing about flask and AppEngine, to having a hello world. Not even taking into consideration all the previous knowledge Jappie already had acquired with docker, Postgres and python itself. Note that at this point we haven’t even made anything of interest. This post was about setting up infrastructure… It is to hope that this story may help some other hackers, so that they can save a few days.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>New new website style changes</title>
    <link href="https://jappieklooster.nl/new-new-website-style-changes.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2018-03-08:/new-new-website-style-changes.html</id>
    <published>2018-03-08T00:00:00Z</published>
    <updated>2018-03-08T00:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="meta"/>
    <summary type="html">&lt;p&gt;Due to circumstances in his life, Jappie Klooster decided it’s time for some more website changes! These are all intended to simply reduce the amount of time it costs maintain this website. This should allow Jappie Klooster to update it more regularly as the friction for updates is decreased.&lt;/p&gt;
&lt;h1 id=&quot;brutalist-style&quot;&gt;Brutalist&lt;/h1&gt;</summary>
    <content type="html">&lt;p&gt;Due to circumstances in his life, Jappie Klooster decided it’s time for some more website changes! These are all intended to simply reduce the amount of time it costs maintain this website. This should allow Jappie Klooster to update it more regularly as the friction for updates is decreased.&lt;/p&gt;
&lt;h1 id=&quot;brutalist-style&quot;&gt;Brutalist style&lt;/h1&gt;
&lt;p&gt;Jappie Klooster became unhappy with the style, although it entertains him endlessly, it may give the wrong idea to a third party. To untrained eyes it may look like he attempted to make it look good (which wasn’t the intention at all). So rather than trying to make it beautiful, Jappie decided to go in full brutalism mode. In essence all style except the most practical ones will be stripped. For reference:&lt;/p&gt;
&lt;h3 id=&quot;old&quot;&gt;old&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/images/2018/old-theme-reference.jpg&quot; alt=&quot;old&quot; /&gt; As the reader see the old style was rather dark themed. It used the linux kernel compilation program as a reference, as discussed &lt;a href=&quot;%7Bfilename%7D/website-launch.md&quot;&gt;in another post&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;new&quot;&gt;new&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/images/2018/new-theme-reference.jpg&quot; alt=&quot;new&quot; /&gt; In the new style Jappie just started deleting html and CSS untill he came accross this, it’s not as brutalist as initially promised, but looks a lot more attractive and was a lot more simple to accomplish.&lt;/p&gt;
&lt;p&gt;Jappie intentionally put the image of the new style in here, even though it’s the current style. It is assumed that this style is not permanent either.&lt;/p&gt;
&lt;h1 id=&quot;getting-rid-of-org-mode&quot;&gt;Getting rid of org mode&lt;/h1&gt;
&lt;p&gt;The believe is still held that org-mode is a superior standard compared to markdown. It can do so many things, such as inline code execution and pipe the result to the document itself, as having full reference support. These are just some of the many great features of org-mode. However org-mode has issues. The fact that it’s entirely confined to Emacs for HTML rendering is a massive problem. Emacs needs to be booted for each article just to do the HTML rendering. There is no easy way Jappie Klooster knows of to keep this process active as a daemon somehow. Technically Emacs can do this, but it is meant to do communication with XORG, not to act as a script execution platform.&lt;/p&gt;
&lt;p&gt;In the future Jappie Klooster may do investigation to make this work fast, however for now the easiest way of increasing building times for this website is to just use the markdown export feature of org-mode. The reason he chose org-mode in the first place as a viable alternative is that it doesn’t try to lock you into it. He now executes this option, because there is simply no time to investigate the preferred route.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Plan prediction</title>
    <link href="https://jappieklooster.nl/plan-prediction.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2017-12-21:/plan-prediction.html</id>
    <published>2017-12-21T12:00:00Z</published>
    <updated>2017-12-21T12:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;For the raster project a main selling point will be the automatic prediction of future scheduling. There are two major schools of thoughts to go with that I know of. Constraint satisfaction solving and data driven approaches (use statistics).&lt;/p&gt;
&lt;p&gt;First of all the most straight forward approach is to use&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;For the raster project a main selling point will be the automatic prediction of future scheduling. There are two major schools of thoughts to go with that I know of. Constraint satisfaction solving and data driven approaches (use statistics).&lt;/p&gt;
&lt;p&gt;First of all the most straight forward approach is to use something like &lt;a href=&quot;https://www.OptaPlanner.org/&quot;&gt;OptaPlanner&lt;/a&gt;. In this approach constraints are laid upon the problem, such as 2 cooks need to at least work on Saturday, but preferably 3. This single constraint has two different part, the hard minimum, and the ‘soft’ preference. With these kind of rules in place, the OptaPlanner can use heuristics to figure out who to plan when. You could add as many constraints as you want, such as have less preference for when employees asked free or let students not work during the day.&lt;/p&gt;
&lt;p&gt;This is a very precise approach and almost surely will work, as other systems have &lt;a href=&quot;https://www.youtube.com/watch?v=sOWC4qrXxFk&amp;amp;index=5&amp;amp;list=PLJY69IMbAdq0uKPnjtWXZ2x7KE1eWg3ns&quot;&gt;demostrated&lt;/a&gt; &lt;a href=&quot;https://github.com/kiegroup/optashift-employee-rostering&quot;&gt;already&lt;/a&gt;. However the issue with this approach is the actual specification of rules. This is quite difficult to do, so for a fact I can’t push this onto the company owners. What I could do is create some kind off helping GUI around it. Or simply use generic predefined rules and if owners want something more sophisticated they should contact me. On top of that the OptaPlanner system I know of is written in Java, which is kind off problematic since I now need to develop some micro-service architecture around it.&lt;/p&gt;
&lt;p&gt;Here is started considering the second approach. The idea I had is that I use the already entered data by the owner to create a statistical model of how he likes to make his plannings. Then we use this model to make future predictions. This requires zero configuration by the owner, and also doesn’t have the language interaction problem as it’s just some calculations. What I imagine is just adding a predict button to the current roster screen that uses the statistical model to magically create a roster.&lt;/p&gt;
&lt;p&gt;Now the method I thought of is simple, it’s an adaptation of &lt;a href=&quot;https://en.wikipedia.org/wiki/Q-learning&quot;&gt;q-learning&lt;/a&gt;, which uses a lookup table for getting action probabilities, if successful probability is increased, otherwise decreased. I’m doing something more simple, here is the gist of it: We count per day how many job types are planned in on average over &lt;em&gt;n&lt;/em&gt; weeks. Then we plan in that amount of job types, for remaining fractions we flip a coin. If someone has asked free we remove him from the potential pool of workers. If there are not enough workers for a job type we just throw a warning for that date and let the owner figure it out.&lt;/p&gt;
&lt;p&gt;The beauty of this technique is that it is simple, but it takes a lot of work out of planning in people. If this is well received there is tons of room for extension. For example naive Bayesian networks can be used to take into account ‘experience’. If we add a reservation datasource somehow prediction could become even more accurate by using it as another influencing factor. Whilst the basic interface remains the same, press the ‘predict’ button and magically you get a roster.&lt;/p&gt;
&lt;p&gt;In conclusion I will attempt a statistical approach rather than OptaPlanner, because it’s more simple. In the future I can still choose to experiment with OptaPlanner. It would be much more interesting to use that, once I know how to register demand accurately, for example the amount of reservations for an evening would be a good indicator for restaurants.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Jakartian Christmas</title>
    <link href="https://jappieklooster.nl/jakartian-christmas.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2017-12-19:/jakartian-christmas.html</id>
    <published>2017-12-19T21:00:00Z</published>
    <updated>2017-12-19T21:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;p&gt;Unfortunately Jesiska couldn’t make it to Australia in time for Christmas. Therefore I decided basically last week to go to Jakarta instead! I personally don’t care much about Christmas, but I thought the office would be closed during this time. (Many companies close in the Netherlands for sure during this&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Unfortunately Jesiska couldn’t make it to Australia in time for Christmas. Therefore I decided basically last week to go to Jakarta instead! I personally don’t care much about Christmas, but I thought the office would be closed during this time. (Many companies close in the Netherlands for sure during this time), and I was just very eager to see Jesiska again.&lt;/p&gt;
&lt;p&gt;I’ve been neglecting this blog a little bit lately, I’ve just been busy, well actually work is a huge time sink.. it sucks. Then I’ve also been trying to increase my income with various project I will discuss next. Although I’ve been neglecting the most important one which is the financial one. It just seems so boring every time I think about it. I need to do this soon because my bonus interest of my savings account will stop at the new year. This holiday conveniently overlaps with that.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://raster.click&quot;&gt;raster&lt;/a&gt; project core is up and running. Basically anyone can sign up to it and take advantage of it for free! Because I haven’t setup payment yet! Because many payment providers ask tax details! Which is difficult to do in Australia!.. I need to go back to the Netherlands sometime to finalize this part. Meanwhile I’m letting my father test it so I can get some feedback. He was genuinely quite excited about the system. This is quite a help because there are just details I don’t think about, such as making sure a week always begins on Monday (rather than it just being whatever day your on), or making the grid clickable so it’s quicker to plan in. etc.&lt;/p&gt;
&lt;p&gt;In the weekend I was hacking with some colleagues on a little app idea we had. This is totally different than the raster project, and I get to work together with some other people. Which is nice cause most of my projects tend to be alone undertakings. Not sure if this going to become anything, although it is ambitious, but we’re keeping it secret for now. What we will do is try and share technical ideas and contribute to the open source community.&lt;/p&gt;
&lt;p&gt;I’ve also been considering applying for permanent residency. I looked into that and apparently to get enough points I need to take an English test. Seems a bit ridicules considering that I’ve done my masters in English, but that’s not the worst part. The English test would cost 300$, and there is no guarantee that I get an high enough score (although I can’t imagine why I wouldn’t, except for my dyslexia).&lt;/p&gt;
&lt;p&gt;What I want most of all is too see Jesiska again. This situation sucks even with all this stuff happening, it’s pointless without Jesiska.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Jappie lives with kangaroos</title>
    <link href="https://jappieklooster.nl/jappie-lives-with-kangaroos.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2017-11-06:/jappie-lives-with-kangaroos.html</id>
    <published>2017-11-06T00:00:00Z</published>
    <updated>2017-11-06T00:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;p&gt;I’ve been living in Australia for well over a month now and I really enjoy it! The first two weeks were quite a wild ride, looking for my first job and finding a permanent place to stay.&lt;/p&gt;
&lt;p&gt;I had 3 interviews appointments prepared before arriving. I finished them in the&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;I’ve been living in Australia for well over a month now and I really enjoy it! The first two weeks were quite a wild ride, looking for my first job and finding a permanent place to stay.&lt;/p&gt;
&lt;p&gt;I had 3 interviews appointments prepared before arriving. I finished them in the first week and managed to get 3 offers. I just choice the one that looked most interesting and also happened to pay the most!&lt;/p&gt;
&lt;p&gt;Finding a house was a whole other level of insanity. I think I’ve been in contact with a scammer, that offered an apartment in the middle of the business district for 900$ per month (900$ per week would be more realistic). All I had to do is deposit some money in a bank account and he would surely sent the keys. In another situation the rent agent wanted me to deposit money into his account for the deposit without signing a contract! What are these people thinking? Rental prices are trough the roof too, I’m paying 330$ per week right now.. That’s about the same amount what I’d pay in the Netherlands per month!&lt;/p&gt;
&lt;p&gt;Things seem to have settled more down now. I have this pattern of a morning training, going to work, go to home and put food in the microwave which I prepared over the weekend.&lt;/p&gt;
&lt;p&gt;I quite enjoy the job too, although it’s a lot less programming than what I expected. A lot of project management is involved too, and QA is super slow.&lt;/p&gt;
&lt;p&gt;Meanwhile I’ve been working on a little side project to try and increase my income. It’s &lt;a href=&quot;http://raster.click&quot; class=&quot;uri&quot;&gt;http://raster.click&lt;/a&gt;, a roster system aimed at restaurants. This is basically re-doing an idea I had when I was younger, but this time I set it up as a service rather than selling the source. This allows me to keep working on it if it becomes adopted by a reasonable amount of people.&lt;/p&gt;
&lt;p&gt;Finally I’ve been trying to come up with a way to invest all this money I’m earning. The banks are much nicer in Australia because you get actual interest. However It’s too low in my opinion. I’ve had several ideas ranging from making an automated trader to start mining crypto currencies.&lt;/p&gt;
&lt;p&gt;Sadly Jesiska hasn’t arrived yet. I’m not even sure if she will before Christmas. It seems to take ages and while I enjoy living like this, it’s not the same without Jesiska. I actually wish I would’ve stayed longer in Indonesia at this point. Oh well we’ll see what happens next.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Work work work, ya ya ya</title>
    <link href="https://jappieklooster.nl/work-work-work-ya-ya-ya.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2017-10-02:/work-work-work-ya-ya-ya.html</id>
    <published>2017-10-02T00:00:00Z</published>
    <updated>2021-08-07T18:17:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;p&gt;Last Wednesday I started my first job at &lt;a href=&quot;https://www.openlearning.com/&quot;&gt;Open Learning&lt;/a&gt;. It has been interesting, I know for a fact I contributed almost nothing to the company up to this point. This is to be expected according to reddit since it’s the first week. I did ask a lot of&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Last Wednesday I started my first job at &lt;a href=&quot;https://www.openlearning.com/&quot;&gt;Open Learning&lt;/a&gt;. It has been interesting, I know for a fact I contributed almost nothing to the company up to this point. This is to be expected according to reddit since it’s the first week. I did ask a lot of questions since I was able to start programming for real yesterday.&lt;/p&gt;
&lt;p&gt;The first today I just spend on getting familiar with the platform and the last day I dabbled around a little in react (hello world!). The reason I have for saying I did little contributions is because I just took up more time of other employees asking questions then producing much. Even the UX work hasn’t been integrated yet because the designer was busy.&lt;/p&gt;
&lt;p&gt;What I didn’t expect however was having a good time over there. I enjoy talking with the various people and the tasks aren’t that bad. There is also a pantry, free fruit and some tea I take advantage of. For lunch we usually go out eating but I’m considering taking lunch as I wanna safe some money especially this first month.&lt;/p&gt;
&lt;p&gt;I noticed a lot of discussions where about food, actually the people at the office seem genuinely really interested in food. Which is good because I like trying new foods. Unfortunately Australia doesn’t seem to have much of local cuisine, but they’ll happily import dishes from neighbouring countries (which are delicious).&lt;/p&gt;
&lt;p&gt;What’s even better is that they allow you to work from home. At this point I can’t really do that yet because I’m a newby and ask a lot of questions, but at some point I also maybe able to do that. Once per week having no travel times would be very good!&lt;/p&gt;
&lt;p&gt;Aside from asking to many questions (in my experience) the only other big issue I have is leaving times. I’m not sure how they decide upon that. Its always kind off awkward for me to leave the place, but on the other hand I also don’t want to do (free) overwork. I think I’m gonna ask about these things because they maybe an issue later.&lt;/p&gt;
&lt;p&gt;The place is nice, the things they’re doing could definitely help society and I enjoy the work (not so much the UX testing part, but it was necessary).&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>What do you think about jakarta</title>
    <link href="https://jappieklooster.nl/what-do-you-think-about-jakarta.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2017-09-28:/what-do-you-think-about-jakarta.html</id>
    <published>2017-09-28T00:00:00Z</published>
    <updated>2017-09-28T00:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;p&gt;Now I’ve finally arrived in Australia, its time to reflect upon my expectations I had for Jakarta. Actually.. While being in Jakarta I got asked this question quite frequently: “What do you think about jakarta?” and I just stood there with no answer. This post is an attempt to answer&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Now I’ve finally arrived in Australia, its time to reflect upon my expectations I had for Jakarta. Actually.. While being in Jakarta I got asked this question quite frequently: “What do you think about jakarta?” and I just stood there with no answer. This post is an attempt to answer that question, and at the same time I address the &lt;a href=&quot;./journey-oceania&quot;&gt;expectations post&lt;/a&gt; I made before.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For Indonesia I’m expecting the population to be better at English then the local Chinese where in China.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;People definitely where better at English than in China, at least in my experience. I had several taxi drivers that could speak some English and even the locals know or try some words. In China only students ever tried to speak English, other people just didn’t want to or couldn’t. I suspect this is in part due to cultural difference. However for China the great Chinese firewall and systematic cultural isolation (that is in part by design) helps to marginalize exposure to English for sure.&lt;/p&gt;
&lt;p&gt;In China learning English is something which parents are willing to pay good money for, but Indonesians are willing to go &lt;em&gt;much&lt;/em&gt; further with international schools. All day to day conversation happens in English in these schools and the entire education system of Singapore is blatantly copied. This turns out in little children walking around malls speaking in an almost perfect British accent with each other. This was such a weird experience to hear perfect British by a 10 year old’s with Bahasa (Indonesian) all around you.&lt;/p&gt;
&lt;p&gt;The schools are a little weird, apparently there coincide 3 different major systems, Indonesian, Chinese and Singapore(/American). However once I thought about this a little I realized we basically have the same in the Netherlands, for example the ‘free schools’ or ‘open schools’.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;My grandfather actually told me many Indonesians would be capable of speaking Dutch. I seriously doubt that&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I was totally right by the way about nobody being able to speak Dutch, I only ever met one person who said something in Dutch to me and it was done in a way where the words didn’t make much sense. They said ‘nice to meet you’ in dutch, without introducing themselves first.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The weather will be hot in Indonesia, at least in Jakarta and there will be lots of rain.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The weather wasn’t that hot actually. Most of the time I was quite comfortable in the Jakarta heat. There was also practically no rain, although one time there was a thunderstorm, which killed the electricity at the place I slept. This caused me to sleep in the heat which is a terrible experience. After this I realized that people in the slums sleep trough this every day. I suddenly felt very bad for those poor souls living there. They probably never get a good night rest.&lt;/p&gt;
&lt;h1 id=&quot;surprises&quot;&gt;Surprises&lt;/h1&gt;
&lt;p&gt;What really surprised me though was the food. If you’re a fan of strong flavoured foods Jakarta is a great place to go! Another thing I didn’t expect was the insane amount of malls. They just casually build three malls next to each other, and then fill it up with schools, fitness clubs and travel agencies, aside from the stuff you’d expect such as shops and restaurants. A reason for the popularity of malls may be the security that keeps out street sellers and the AC which makes walking around there much more pleasant.&lt;/p&gt;
&lt;p&gt;Another really nice thing was the thousand island trip. So this is basically a boat ride of about an hour to one of the islands on the coast of Jakarta. However it’s really similar to Aruba for about a tenth of the cost to get there.&lt;/p&gt;
&lt;p&gt;Okay so here we’re kind off getting out of Jakarta, but what I really really recommend is the night safari. You’re being taken around the zoo in a little train, although it goes a little to fast to experience well, and can’t take pictures for sure. However it also includes a theme park and taking pictures with baby animals (need to pay a little for the animals but it includes the opportunity).&lt;/p&gt;
&lt;p&gt;What’s really strange to see is that some people, have as job, guiding traffic but they’re not employed by government. They just sort off start guiding traffic on their own and then live of the tips. A similar kind of people do the same for parking, they’re just living parking meters, but they also help with getting in and out and making sure you park straight. As a consequence all cars are parked really nicely.&lt;/p&gt;
&lt;p&gt;Finally another peculiar thing is that there are &lt;strong&gt;so&lt;/strong&gt; many people self employed, it’s ridiculous if you think about it. Little shops everywhere, the traffic people, parking people etc. All self employed. I think this is a major difference from the developed world, where you generally start working for a boss because it just pays that much better. But with those low wages, it’s just that more attractive to start for yourself.&lt;/p&gt;
&lt;h1 id=&quot;so-what-do-i-think-about-jakarta&quot;&gt;So what do I think about Jakarta?&lt;/h1&gt;
&lt;p&gt;I think that Jakarta is like an uncut gem. It already has some really attractive attributes, but until issues such as the crazy traffic and drinkable tap water are addressed it isn’t as good as it could be. Still it was an amazing experience to be there and I’d definitely come back for the food alone.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Beginning of eternal summer</title>
    <link href="https://jappieklooster.nl/beginning-of-eternal-summer.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2017-08-16:/beginning-of-eternal-summer.html</id>
    <published>2017-08-16T16:00:00Z</published>
    <updated>2017-08-16T16:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="story"/>
    <summary type="html">&lt;p&gt;Right now I’m in the airport waiting to go to Jakarta. It’s really weird what I’m doing I think, few people actually travel alone by plane, but in my case I’m just sort of emigrating and finding a job in a foreign country.&lt;/p&gt;
&lt;p&gt;I want to try and do an&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Right now I’m in the airport waiting to go to Jakarta. It’s really weird what I’m doing I think, few people actually travel alone by plane, but in my case I’m just sort of emigrating and finding a job in a foreign country.&lt;/p&gt;
&lt;p&gt;I want to try and do an eternal summer. What this entails is basically following the pattern of migration birds, once winter come you move south, where it’s warmer. In my case, when dutch winter comes, I’m going all the way south to Australia, where winter just is about to end and summer is about to begin and when Australian winter comes I go back again. This probably won’t work if I get a good job in Sydney. However getting a programmer job right now looks like a big hurdle.&lt;/p&gt;
&lt;p&gt;I listened to freakonomics that told me most of the population is over educated, which means that people with master degrees are competing for entry level positions, and people with bachelors are again competing for even more lower level positions. IE, it’s crowded at the top, which pushes competition downwards. This seriously disturbed me, because I started doing this too. For example, I started replying to junior positions because it looked like nobody reacted to my other letters. I must have applied to over 50 positions right now. Being a foreigner also doesn’t help I think. At this point I would love to do the low level trainee-ship (Java 101) they offered me in the Netherlands except then in Sydney. I still hope this can be done, like at this point the economy is growing again right? People need more programmers right? Nope, I think the job market tends to lag behind economic numbers.&lt;/p&gt;
&lt;p&gt;However when I arrive in Indonesia I’ll be doing a holiday first. Not only that I’m expecting to work a little on the web shop system I’m building, and maybe even do some applying. Of course just in the evenings, when I’m not doing cool traveling stuff.&lt;/p&gt;
&lt;p&gt;I’m also thinking about tracking the stuff I’m doing in Indonesia holiday a little on the blog in a journal kind off style, I know nobody is reading this but &lt;strong&gt;I&lt;/strong&gt; like writing this. Directly encoding images etc, would also be nice.&lt;/p&gt;
&lt;p&gt;Maybe I’ll also add my Chinese journeys to the blog. I at least have the journal of my second voyage in the bag. which I don’t have yet digitally. In the passed however I usually started full of enthusiasm with recording but after a while I got bored of it. Perhaps I should take it more casually and just spend a limited amount of time on it. Actually that maybe a good idea because then I’ll only record interesting stuff. And it help with motivation because I’ll think “Oh these 20 minutes are over quickly”.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Journey to Oceania</title>
    <link href="https://jappieklooster.nl/journey-to-oceania.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2017-08-07:/journey-to-oceania.html</id>
    <published>2017-08-07T22:00:00Z</published>
    <updated>2017-08-07T22:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="story"/>
    <summary type="html">&lt;p&gt;Wednesday 2017-08-16 I’ll leave towards Oceania. First I will go for a month to Indonesia, having a little holiday and meeting my almost girlfriend. Then I will move on to Australia to do a “working holiday”, where I hope to do my profession, as a software engineer or work in&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Wednesday 2017-08-16 I’ll leave towards Oceania. First I will go for a month to Indonesia, having a little holiday and meeting my almost girlfriend. Then I will move on to Australia to do a “working holiday”, where I hope to do my profession, as a software engineer or work in AI (think either data mining or machine learning).&lt;/p&gt;
&lt;p&gt;This is the second major journey I undertake, which in my case means being away for more than three months. This time I’m expecting to stay away for at least six months, depending on if I can get good work and a visa. Perhaps I’ll write in a later blog post about the first journey I undertook to China, where I had a great time and which motivated me to leave again. In this blog post however I’ll record my expectations for this journey, so that one day I can look back and see what a fool I was.&lt;/p&gt;
&lt;p&gt;For Indonesia I’m expecting the population to be better at English then the local Chinese where in China. A Chinese man can say with quite some confidence he’s not going to encounter many foreigners in his life, in fact I had people tell me this when I was there, Which is in stark contrast to Dutch mentality where you expect to encounter many foreigners and thus you’d have to learn at least English and either German or French (all three also is common). I also expect Indonesians to be willing to learn more foreign tongues, because they don’t have a common tongue such as the Chinese have with Mandarin (in fact there are thousand of languages in Indonesia), which means they’re expecting to meet people that don’t know their native language, and thus English will be used as lingua franca. especially on Bali island everyone will know English because of tourism and also in Jakarta, but to a lesser extend.&lt;/p&gt;
&lt;p&gt;My grandfather actually told me many Indonesians would be capable of speaking Dutch. I seriously doubt that, and my (almost) girlfriend has confirmed this is only true for older Indonesians. My Indonesian girlfriend has also warned me life is slower in Indonesia than in China (which was already pretty laid back). By this I think she means that people aren’t too strict with appointments and that we can expect to wait for stuff to happen.&lt;/p&gt;
&lt;p&gt;The weather will be hot in Indonesia, at least in Jakarta and there will be lots of rain. I know this because we talk often about the weather and I’m pretty sure it rains there more. Another environmental thing is that there will be lots of traffic in Jakarta, and especially many scooters and motorbikes. Probably similarly to the amount of &lt;a href=&quot;https://en.wikipedia.org/wiki/Guilin&quot;&gt;Guilin&lt;/a&gt;, actually the climate maybe also similar to Guilin summer times.&lt;/p&gt;
&lt;p&gt;Australia is a whole other beast of course. Everyone will speak English there and I’ll probably communicate quite easily. My grandfather thought I’d have some problems with Australian English, but I doubt that. I mean perhaps I have to get used to it for a week, but that pales in comparison to the efforts I had to take for learning the heavy accents of mainland Chinese people.&lt;/p&gt;
&lt;p&gt;I do expect Australians to be incredibly polite and somewhat more laid back than Dutch people, however still ‘faster life’ than in China and Indonesia. By politeness I mean, trying to keep a kind off distance from strangers and embezzling your words so they sound ‘better’. This politeness of course breaks down between friends.&lt;/p&gt;
&lt;p&gt;I’m expecting Sydney to be dominated by cars. Like cars to the extreme. Whereas in the Netherlands we use bicycles, you can get anywhere by car in Sydney. I’m expecting Sydney to be about the size of &lt;a href=&quot;https://en.wikipedia.org/wiki/Xiamen&quot;&gt;Xiamen&lt;/a&gt;. Although much less dense (because of the cars needing their space). Sydney will probably have about the same weather as the Netherlands, laying a lot farther south than Indonesia, although with the seasons mirrored of course.&lt;/p&gt;
&lt;p&gt;My friends also told me Australia is a very deadly place, where everything tries to kill you. I think that’s highly exaggerated, mostly because people tend to put as much distance between themselves and nature as possible, especially in cities.&lt;/p&gt;
&lt;p&gt;It’s a little short but there is it, a quick overview of my expectations for these two countries. Probably full of stereo types, but this is why I do the journey.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Travel is fatal to prejudice, bigotry, and narrow-mindedness, and many of our people need it sorely on these accounts. Broad, wholesome, charitable views of men and things cannot be acquired by vegetating in one little corner of the earth all one’s lifetime. – Mark Twain&lt;/p&gt;
&lt;/blockquote&gt;</content>
  </entry>
  <entry>
    <title>My thesis</title>
    <link href="https://jappieklooster.nl/my-thesis.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2017-07-07:/my-thesis.html</id>
    <published>2017-07-07T00:00:00Z</published>
    <updated>2017-07-07T00:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;p&gt;I’m done. The master in AI is complete. I finished the thesis about adding `Jungian personality in a chatbot’. In this blog post I will give a summery and some comments from a programmers’ perspective that just don’t fit in a thesis. For example, the implementation are not at all&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;I’m done. The master in AI is complete. I finished the thesis about adding `Jungian personality in a chatbot’. In this blog post I will give a summery and some comments from a programmers’ perspective that just don’t fit in a thesis. For example, the implementation are not at all important, but I like talking about using Java in a functional programming style and the pains this caused.&lt;/p&gt;
&lt;p&gt;The source is available &lt;a href=&quot;https://jappieklooster.nl/chatbot&quot;&gt;here&lt;/a&gt;, for anyone interested. The full text is available &lt;a href=&quot;https://jappieklooster.nl/thesis&quot;&gt;here&lt;/a&gt; (and &lt;a href=&quot;https://github.com/jappeace/methods-homework/blob/master/thesis/thesis.org&quot;&gt;thesis source&lt;/a&gt;). The presentation I did can be found &lt;a href=&quot;https://jappieklooster.nl/presents/thesis&quot;&gt;here&lt;/a&gt; (and it’s &lt;a href=&quot;https://github.com/jappeace/methods-homework/blob/master/thesis/presentation.org&quot;&gt;source&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I start by discussing what the thesis was about in a summery (for those who don’t want to read about 80 pages). after that I’ll talk about the implementation details (I just want to lay my egg). Finally I will give an overview of the experience, including the defence (for those who didn’t do a master, it maybe interesting),&lt;/p&gt;
&lt;h1 id=&quot;what-did-i-do&quot;&gt;What did I do?&lt;/h1&gt;
&lt;p&gt;I build a very fancy chatbot called Gaia, which is &lt;strong&gt;not&lt;/strong&gt; based upon ALICE. The core is a business rule engine called Drools &lt;span class=&quot;citation&quot; data-cites=&quot;vcimbora2015usability&quot;&gt;cite:vcimbora2015usability&lt;/span&gt;. Once the scenario described by YAML files are read, everything chatbot related happens in Drools. This means you can make it as smart as you want, for example you can make a rule that detects when a user is starting to repeat himself (and deal with that), or use timers that are native to drools to create a bot that acts impatiently. Pattern matching also happens inside drools, which means your not stuck to the regex system I provided. Unlike the ALICE chatbot where you &lt;strong&gt;have&lt;/strong&gt; to use the ALICE patterns (which are less power full than regular expressions).&lt;/p&gt;
&lt;p&gt;That was made to just to get started with personality. The issue with the ALICE chatbot was that it already predefined a response before any deliberation could happen. What I did was simply separating the `figure out what user said’ step from the `this needs to happen next’ steps. To make this separation more clear lets look at the syntax of both systems. AIML, which is the core of the ALICE chatbot looks like source block &lt;a href=&quot;code:aiml&quot;&gt;code:aiml&lt;/a&gt;. A diagram representation of this block can be seen in figure &lt;a href=&quot;fig:dep:aimlcats&quot;&gt;fig:dep:aimlcats&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
AIML syntax for a reply
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;code:aiml&quot;&gt;&lt;pre class=&quot;sourceCode xml&quot;&gt;&lt;code class=&quot;sourceCode xml&quot;&gt;&lt;span id=&quot;code:aiml-1&quot;&gt;&lt;a href=&quot;#code:aiml-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;&lt;span class=&quot;kw&quot;&gt;aiml&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-2&quot;&gt;&lt;a href=&quot;#code:aiml-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &amp;lt;&lt;span class=&quot;kw&quot;&gt;categroy&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-3&quot;&gt;&lt;a href=&quot;#code:aiml-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &amp;lt;&lt;span class=&quot;kw&quot;&gt;pattern&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-4&quot;&gt;&lt;a href=&quot;#code:aiml-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            Hello&lt;/span&gt;
&lt;span id=&quot;code:aiml-5&quot;&gt;&lt;a href=&quot;#code:aiml-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &amp;lt;/&lt;span class=&quot;kw&quot;&gt;pattern&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-6&quot;&gt;&lt;a href=&quot;#code:aiml-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &amp;lt;&lt;span class=&quot;kw&quot;&gt;template&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-7&quot;&gt;&lt;a href=&quot;#code:aiml-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            Hi&lt;/span&gt;
&lt;span id=&quot;code:aiml-8&quot;&gt;&lt;a href=&quot;#code:aiml-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &amp;lt;/&lt;span class=&quot;kw&quot;&gt;template&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-9&quot;&gt;&lt;a href=&quot;#code:aiml-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &amp;lt;/&lt;span class=&quot;kw&quot;&gt;categroy&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-10&quot;&gt;&lt;a href=&quot;#code:aiml-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &amp;lt;&lt;span class=&quot;kw&quot;&gt;category&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-11&quot;&gt;&lt;a href=&quot;#code:aiml-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &amp;lt;&lt;span class=&quot;kw&quot;&gt;pattern&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-12&quot;&gt;&lt;a href=&quot;#code:aiml-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            How are you&lt;/span&gt;
&lt;span id=&quot;code:aiml-13&quot;&gt;&lt;a href=&quot;#code:aiml-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &amp;lt;/&lt;span class=&quot;kw&quot;&gt;pattern&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-14&quot;&gt;&lt;a href=&quot;#code:aiml-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &amp;lt;&lt;span class=&quot;kw&quot;&gt;template&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-15&quot;&gt;&lt;a href=&quot;#code:aiml-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            Not doing too well today.&lt;/span&gt;
&lt;span id=&quot;code:aiml-16&quot;&gt;&lt;a href=&quot;#code:aiml-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &amp;lt;/&lt;span class=&quot;kw&quot;&gt;template&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-17&quot;&gt;&lt;a href=&quot;#code:aiml-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &amp;lt;/&lt;span class=&quot;kw&quot;&gt;category&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-18&quot;&gt;&lt;a href=&quot;#code:aiml-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &amp;lt;&lt;span class=&quot;kw&quot;&gt;category&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-19&quot;&gt;&lt;a href=&quot;#code:aiml-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &amp;lt;&lt;span class=&quot;kw&quot;&gt;pattern&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-20&quot;&gt;&lt;a href=&quot;#code:aiml-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            How * you&lt;/span&gt;
&lt;span id=&quot;code:aiml-21&quot;&gt;&lt;a href=&quot;#code:aiml-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &amp;lt;/&lt;span class=&quot;kw&quot;&gt;pattern&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-22&quot;&gt;&lt;a href=&quot;#code:aiml-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &amp;lt;&lt;span class=&quot;kw&quot;&gt;template&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-23&quot;&gt;&lt;a href=&quot;#code:aiml-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &amp;lt;&lt;span class=&quot;kw&quot;&gt;srai&lt;/span&gt;&amp;gt;How are you&amp;lt;/&lt;span class=&quot;kw&quot;&gt;srai&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-24&quot;&gt;&lt;a href=&quot;#code:aiml-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &amp;lt;/&lt;span class=&quot;kw&quot;&gt;template&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-25&quot;&gt;&lt;a href=&quot;#code:aiml-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &amp;lt;/&lt;span class=&quot;kw&quot;&gt;category&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span id=&quot;code:aiml-26&quot;&gt;&lt;a href=&quot;#code:aiml-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;/&lt;span class=&quot;kw&quot;&gt;aiml&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;./images/2017/uml/dep:aimlcats.svg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Now let’s look at the new representation I came up with in source blocks &lt;a href=&quot;code:yaml:greeting&quot;&gt;code:yaml:greeting&lt;/a&gt;, &lt;a href=&quot;code:yaml:how&quot;&gt;code:yaml:how&lt;/a&gt;, &lt;a href=&quot;code:yaml:not&quot;&gt;code:yaml:not&lt;/a&gt; and &lt;a href=&quot;code:yaml:connections&quot;&gt;code:yaml:connections&lt;/a&gt;. Of which I made a diagram in figure &lt;a href=&quot;fig:dep:aimlsyms&quot;&gt;fig:dep:aimlsyms&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
Gaia yaml &lt;code class=&quot;verbatim&quot;&gt;greeting.yml&lt;/code&gt; file
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;code:yaml:greeting&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&quot;&gt;&lt;span id=&quot;code:yaml:greeting-1&quot;&gt;&lt;a href=&quot;#code:yaml:greeting-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;literals&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:greeting-2&quot;&gt;&lt;a href=&quot;#code:yaml:greeting-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; Hi&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:greeting-3&quot;&gt;&lt;a href=&quot;#code:yaml:greeting-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; Hello&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
Gaia yaml &lt;code class=&quot;verbatim&quot;&gt;status_inquery.yml&lt;/code&gt; file
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;code:yaml:how&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&quot;&gt;&lt;span id=&quot;code:yaml:how-1&quot;&gt;&lt;a href=&quot;#code:yaml:how-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;literals&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:how-2&quot;&gt;&lt;a href=&quot;#code:yaml:how-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; How are you?&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:how-3&quot;&gt;&lt;a href=&quot;#code:yaml:how-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;patterns&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:how-4&quot;&gt;&lt;a href=&quot;#code:yaml:how-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; How * you&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:how-5&quot;&gt;&lt;a href=&quot;#code:yaml:how-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; How are you *&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
Gaia yaml &lt;code class=&quot;verbatim&quot;&gt;reply_bad.yml&lt;/code&gt; file
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;code:yaml:not&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&quot;&gt;&lt;span id=&quot;code:yaml:not-1&quot;&gt;&lt;a href=&quot;#code:yaml:not-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;literals&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:not-2&quot;&gt;&lt;a href=&quot;#code:yaml:not-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; Not doing too well today.&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:not-3&quot;&gt;&lt;a href=&quot;#code:yaml:not-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;regexes&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:not-4&quot;&gt;&lt;a href=&quot;#code:yaml:not-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; doing (*.) badly&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
Gaia yaml &lt;code class=&quot;verbatim&quot;&gt;_connections.yml&lt;/code&gt; file
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;code:yaml:connections&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&quot;&gt;&lt;span id=&quot;code:yaml:connections-1&quot;&gt;&lt;a href=&quot;#code:yaml:connections-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:connections-2&quot;&gt;&lt;a href=&quot;#code:yaml:connections-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; greeting&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:connections-3&quot;&gt;&lt;a href=&quot;#code:yaml:connections-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:connections-4&quot;&gt;&lt;a href=&quot;#code:yaml:connections-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; greeting&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:connections-5&quot;&gt;&lt;a href=&quot;#code:yaml:connections-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; status_inquery&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:connections-6&quot;&gt;&lt;a href=&quot;#code:yaml:connections-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;pp&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:connections-7&quot;&gt;&lt;a href=&quot;#code:yaml:connections-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:connections-8&quot;&gt;&lt;a href=&quot;#code:yaml:connections-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; status_inquery&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:connections-9&quot;&gt;&lt;a href=&quot;#code:yaml:connections-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:connections-10&quot;&gt;&lt;a href=&quot;#code:yaml:connections-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; reply_bad&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:connections-11&quot;&gt;&lt;a href=&quot;#code:yaml:connections-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;restricted_to&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; patient&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;./images/2017/uml/dep:aimlsyms.svg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The new representation looks quite verbose too, but it does much more modelling than the original. Additionally, we separated the concerns of legal connections, from pattern matching. Modelling the scenario now almost entirely happens in the &lt;sub&gt;connections&lt;/sub&gt; file, and while doing that you don’t have to deal with pattern matching. Using the file names as identifies guarantees uniqueness.&lt;/p&gt;
&lt;p&gt;We can model complicated examples such as in source block &lt;a href=&quot;code:yaml:complex&quot;&gt;code:yaml:complex&lt;/a&gt;. This can be seen as a diagram in figure &lt;a href=&quot;fig:dep:filedconns&quot;&gt;fig:dep:filedconns&lt;/a&gt;. Trying to put such an example in AIML is basically impossible. First of all the concept of actors doesn’t exist, secondly categories can’t model the availability of choice. There are &lt;a href=&quot;http://www.alicebot.org/documentation/aiml-reference.html#if&quot;&gt;if&lt;/a&gt; statements, but that’s making the decision in place. Aside from the fact you shouldn’t do &lt;a href=&quot;http://wiki.c2.com/?XmlSucks&quot;&gt;conditionals in xml&lt;/a&gt; structurally.&lt;/p&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
Connections grouped into a file
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;code:yaml:complex&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&quot;&gt;&lt;span id=&quot;code:yaml:complex-1&quot;&gt;&lt;a href=&quot;#code:yaml:complex-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-2&quot;&gt;&lt;a href=&quot;#code:yaml:complex-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; greeting&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-3&quot;&gt;&lt;a href=&quot;#code:yaml:complex-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-4&quot;&gt;&lt;a href=&quot;#code:yaml:complex-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; greeting&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-5&quot;&gt;&lt;a href=&quot;#code:yaml:complex-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; ask_reason_here&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-6&quot;&gt;&lt;a href=&quot;#code:yaml:complex-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;restricted_to&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; doctor&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-7&quot;&gt;&lt;a href=&quot;#code:yaml:complex-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;pp&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-8&quot;&gt;&lt;a href=&quot;#code:yaml:complex-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-9&quot;&gt;&lt;a href=&quot;#code:yaml:complex-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; ask_reason_here&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-10&quot;&gt;&lt;a href=&quot;#code:yaml:complex-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-11&quot;&gt;&lt;a href=&quot;#code:yaml:complex-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;restricted_to&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; patient&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-12&quot;&gt;&lt;a href=&quot;#code:yaml:complex-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; need_medicine&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-13&quot;&gt;&lt;a href=&quot;#code:yaml:complex-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;restricted_to&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; patient&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-14&quot;&gt;&lt;a href=&quot;#code:yaml:complex-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; broken_arms&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-15&quot;&gt;&lt;a href=&quot;#code:yaml:complex-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;restricted_to&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; patient&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-16&quot;&gt;&lt;a href=&quot;#code:yaml:complex-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; feel_sick&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-17&quot;&gt;&lt;a href=&quot;#code:yaml:complex-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;pp&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-18&quot;&gt;&lt;a href=&quot;#code:yaml:complex-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-19&quot;&gt;&lt;a href=&quot;#code:yaml:complex-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; need_medicine&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-20&quot;&gt;&lt;a href=&quot;#code:yaml:complex-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; greeting&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-21&quot;&gt;&lt;a href=&quot;#code:yaml:complex-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-22&quot;&gt;&lt;a href=&quot;#code:yaml:complex-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;restricted_to&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; doctor         &lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-23&quot;&gt;&lt;a href=&quot;#code:yaml:complex-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; why_need&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;code:yaml:complex-24&quot;&gt;&lt;a href=&quot;#code:yaml:complex-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; status_inquery&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;./images/2017/uml/dep:filedconns.svg&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-personality-stuff&quot;&gt;The personality stuff&lt;/h2&gt;
&lt;p&gt;With the availability of choice in place, I could do the personality stuff. Jung’s theory is used for personality to decide what the algorithm should use, this is also the core theory of for example MBTI. Jung said that each function has an attitude, either introversion or extroversion. Introversion deals with the inside world, memories and ideas. Extroversion deals with the outside world, which can be seen. An overview of the function can be seen here: &lt;span class=&quot;math display&quot;&gt;𝒥 = {&lt;em&gt;T&lt;/em&gt;&lt;sub&gt;&lt;em&gt;e&lt;/em&gt;&lt;/sub&gt;, &lt;em&gt;T&lt;/em&gt;&lt;sub&gt;&lt;em&gt;i&lt;/em&gt;&lt;/sub&gt;, &lt;em&gt;F&lt;/em&gt;&lt;sub&gt;&lt;em&gt;e&lt;/em&gt;&lt;/sub&gt;, &lt;em&gt;F&lt;/em&gt;&lt;sub&gt;&lt;em&gt;i&lt;/em&gt;&lt;/sub&gt;, &lt;em&gt;S&lt;/em&gt;&lt;sub&gt;&lt;em&gt;e&lt;/em&gt;&lt;/sub&gt;, &lt;em&gt;S&lt;/em&gt;&lt;sub&gt;&lt;em&gt;i&lt;/em&gt;&lt;/sub&gt;, &lt;em&gt;N&lt;/em&gt;&lt;sub&gt;&lt;em&gt;e&lt;/em&gt;&lt;/sub&gt;, &lt;em&gt;N&lt;/em&gt;&lt;sub&gt;&lt;em&gt;i&lt;/em&gt;&lt;/sub&gt;}&lt;/span&gt; Each of these does something different, for the entire description I refer to the thesis or this source &lt;span class=&quot;citation&quot; data-cites=&quot;hall1973primer&quot;&gt;cite:hall1973primer&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;What we wanted is that these functions would plan ahead in cooperation with each other. This would be personality as a process rather than value based &lt;span class=&quot;citation&quot; data-cites=&quot;campos_mabs2009&quot;&gt;cite:campos_mabs2009&lt;/span&gt;, this was a requirement by my teacher. To do this we introduced the dialogue tree data structure: &lt;span class=&quot;math display&quot;&gt;&lt;em&gt;u&lt;/em&gt; = (&lt;em&gt;a&lt;/em&gt;, &lt;em&gt;s&lt;/em&gt;)&lt;/span&gt; &lt;span class=&quot;math display&quot;&gt;&lt;em&gt;D&lt;/em&gt; = (&lt;em&gt;u&lt;/em&gt;, [&lt;em&gt;D&lt;/em&gt;])&lt;/span&gt;&lt;/p&gt;
&lt;table id=&quot;tab:dialoguetree&quot;&gt;
&lt;caption&gt;Description of symbols&lt;/caption&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td&gt;&amp;lt;&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;math inline&quot;&gt;&lt;em&gt;u&lt;/em&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;Utterance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;math inline&quot;&gt;&lt;em&gt;a&lt;/em&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;Actor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;math inline&quot;&gt;&lt;em&gt;s&lt;/em&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;Symbol&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;math inline&quot;&gt;&lt;em&gt;D&lt;/em&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;Dialogue Tree&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Where &lt;span class=&quot;math inline&quot;&gt;&lt;em&gt;u&lt;/em&gt;&lt;/span&gt; is an utterance, &lt;span class=&quot;math inline&quot;&gt;&lt;em&gt;a&lt;/em&gt;&lt;/span&gt; an actor, &lt;span class=&quot;math inline&quot;&gt;&lt;em&gt;s&lt;/em&gt;&lt;/span&gt; a symbol and &lt;span class=&quot;math inline&quot;&gt;&lt;em&gt;D&lt;/em&gt;&lt;/span&gt; the dialogue tree (see table &lt;a href=&quot;tab:dialoguetree&quot;&gt;tab:dialoguetree&lt;/a&gt;). With this data structure we can plan ahead, each node is an utterance made that can have multiple possible responses (see figure &lt;a href=&quot;fig:dialoguetree&quot;&gt;fig:dialoguetree&lt;/a&gt;). What we then pass this dialogue tree trough the functions either growing or sorting on preference. Each function in the personality can do modification, but the order of execution determines their `strength’.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/2017/uml/dialoguetree.svg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We assumed that Jung meant that action generation was done by irrational functions, and preference ordering by rationale. What we did was giving all these functions the same &lt;em&gt;type signature&lt;/em&gt; and then putting them into an order. This looked with the Haskell notation like the following: &lt;span class=&quot;math display&quot;&gt;$$ \left (\overset{next}{B \to D \to (B, D)}\right ) \to B \to D \overset{f_a}{\to} (B, D) $$&lt;/span&gt; The &lt;em&gt;next&lt;/em&gt; argument allows us to encode a sequence of functions, however this was problematic because I was asked to make operation in between functions available to the drools rule engine &lt;span class=&quot;citation&quot; data-cites=&quot;droolsdocs vcimbora2015usability&quot;&gt;cite:droolsdocs,vcimbora2015usability&lt;/span&gt;. We ended up with a hybrid approach where the functions were stored in a list and drools parsed them, but they could also be composed. Actually if I could change anything of the thesis it would be this part, it’s kind-off messy right now, but I simply didn’t have any more time left to figure this out properly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/2017/uml/jungjavaclass.svg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;How this looked in java can be seen in figure &lt;a href=&quot;fig:jungjavaclass&quot;&gt;fig:jungjavaclass&lt;/a&gt;. The core is the enumeration of Jungian Functions, they all have the same type signature with &lt;code class=&quot;verbatim&quot;&gt;JungFuncArgs&lt;/code&gt; as argument and result. These arguments can be modified by the functions and they can use apply next to apply the next function in the sequence to the arguments. This is only part of the story, not telling about how drools rules deal with the functions in order, but they are simply functions with as input &lt;code class=&quot;verbatim&quot;&gt;JungFuncArgs&lt;/code&gt; and as output. Which means they are &lt;a href=&quot;https://en.wikipedia.org/wiki/Endomorphism&quot;&gt;endomorphisms&lt;/a&gt;. I was tempted to put that in the title, because it sounds impressive, but then I realized it’s just a minor part of my thesis, and I think that part is messy.&lt;/p&gt;
&lt;h3 id=&quot;steering&quot;&gt;Steering&lt;/h3&gt;
&lt;p&gt;To steer dialogue two major methods are used. Feeling functions use perlocutionary values as directions, which is based upon speech act theory &lt;span class=&quot;citation&quot; data-cites=&quot;shoham2008multiagent&quot;&gt;cite:shoham2008multiagent&lt;/span&gt;, and as an example can be seen in source block &lt;a href=&quot;yaml:values&quot;&gt;yaml:values&lt;/a&gt;. The numbers used per perlocutionary value can differ per agent, their names can be attached to connections, see source block &lt;a href=&quot;yaml:values:connections&quot;&gt;yaml:values:connections&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
Values in &lt;code class=&quot;verbatim&quot;&gt;believes.yml&lt;/code&gt;
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;yaml:values&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&quot;&gt;&lt;span id=&quot;yaml:values-1&quot;&gt;&lt;a href=&quot;#yaml:values-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:values-2&quot;&gt;&lt;a href=&quot;#yaml:values-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;enthusiasm&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;8&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:values-3&quot;&gt;&lt;a href=&quot;#yaml:values-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;polite&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
Value example connections &lt;code class=&quot;verbatim&quot;&gt;_connection.yaml&lt;/code&gt;
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;yaml:values:connections&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&quot;&gt;&lt;span id=&quot;yaml:values:connections-1&quot;&gt;&lt;a href=&quot;#yaml:values:connections-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:values:connections-2&quot;&gt;&lt;a href=&quot;#yaml:values:connections-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; greeting&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:values:connections-3&quot;&gt;&lt;a href=&quot;#yaml:values:connections-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:values:connections-4&quot;&gt;&lt;a href=&quot;#yaml:values:connections-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; greeting &lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:values:connections-5&quot;&gt;&lt;a href=&quot;#yaml:values:connections-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:values:connections-6&quot;&gt;&lt;a href=&quot;#yaml:values:connections-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; Polite&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:values:connections-7&quot;&gt;&lt;a href=&quot;#yaml:values:connections-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; status&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:values:connections-8&quot;&gt;&lt;a href=&quot;#yaml:values:connections-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;restricted_to&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; patient&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:values:connections-9&quot;&gt;&lt;a href=&quot;#yaml:values:connections-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:values:connections-10&quot;&gt;&lt;a href=&quot;#yaml:values:connections-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; Polite&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:values:connections-11&quot;&gt;&lt;a href=&quot;#yaml:values:connections-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; Enthusiasm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Thinking functions go primarily towards goals and can be seen in source block &lt;a href=&quot;yaml:goals&quot;&gt;yaml:goals&lt;/a&gt;. What we do is marking that we want certain symbols to be uttered by a particular actor. In the example the patient want the doctor to utter “Have some painkillers”. Goals are entirely encoded in the believes.&lt;/p&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
Goals in &lt;code class=&quot;verbatim&quot;&gt;believes.yml&lt;/code&gt;
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;yaml:goals&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&quot;&gt;&lt;span id=&quot;yaml:goals-1&quot;&gt;&lt;a href=&quot;#yaml:goals-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;goals&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:goals-2&quot;&gt;&lt;a href=&quot;#yaml:goals-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;actor&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; doctor&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:goals-3&quot;&gt;&lt;a href=&quot;#yaml:goals-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;scene&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; diagnoses&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:goals-4&quot;&gt;&lt;a href=&quot;#yaml:goals-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; have_painkillers&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:goals-5&quot;&gt;&lt;a href=&quot;#yaml:goals-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;actor&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; patient&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:goals-6&quot;&gt;&lt;a href=&quot;#yaml:goals-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;scene&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; information_gathering&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:goals-7&quot;&gt;&lt;a href=&quot;#yaml:goals-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; back_pain&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To encode the personality we simply specify which Jungian functions we want in what order, see source block &lt;a href=&quot;yaml:personality&quot;&gt;yaml:personality&lt;/a&gt;. In the thesis we specifically used MBTI &lt;span class=&quot;citation&quot; data-cites=&quot;website.mbtitypedynamics&quot;&gt;cite:website.mbtitypedynamics&lt;/span&gt; as a guide line, but the PPSDQ &lt;span class=&quot;citation&quot; data-cites=&quot;kier1997new king1999score&quot;&gt;cite:kier1997new,king1999score&lt;/span&gt; and SL-TDI &lt;span class=&quot;citation&quot; data-cites=&quot;arnau2000reliability&quot;&gt;cite:arnau2000reliability&lt;/span&gt; can also be represented like this. Although some work needs to be done to add scalar values they require.&lt;/p&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
Personality in &lt;code class=&quot;verbatim&quot;&gt;believes.yml&lt;/code&gt;
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;yaml:personality&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&quot;&gt;&lt;span id=&quot;yaml:personality-1&quot;&gt;&lt;a href=&quot;#yaml:personality-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# ENFP&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:personality-2&quot;&gt;&lt;a href=&quot;#yaml:personality-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;personality&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;at&quot;&gt;Ne&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; Fi&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; Te&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; Si&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Finally we need to specify all actors, in case a connection didn’t specify which actors are available, and we need to specify which actor the agent is. We need to do this because we model both sides of the conversation, so actors need to be specified explicitly, an example can be seen in source block &lt;a href=&quot;yaml:actors&quot;&gt;yaml:actors&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
Actors in &lt;code class=&quot;verbatim&quot;&gt;believes.yml&lt;/code&gt;
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;yaml:actors&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&quot;&gt;&lt;span id=&quot;yaml:actors-1&quot;&gt;&lt;a href=&quot;#yaml:actors-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; patient&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:actors-2&quot;&gt;&lt;a href=&quot;#yaml:actors-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;actors&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:actors-3&quot;&gt;&lt;a href=&quot;#yaml:actors-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; patient&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;yaml:actors-4&quot;&gt;&lt;a href=&quot;#yaml:actors-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; doctor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With all of this in place the varied personalities can go over different modeled paths. Which is sort of what my thesis was about I guess. We did not specified values (unless you count perlocutionary values and goals), and the personality process will figure out what paths to take.&lt;/p&gt;
&lt;h1 id=&quot;crazy-programming-stuff&quot;&gt;Crazy programming stuff&lt;/h1&gt;
&lt;p&gt;Ok ok, so now we have some context we can go to some of the more interesting parts (to me at least). I wasn’t allowed to go into the details of the programming techniques I applied, but boy did I do some interesting things.&lt;/p&gt;
&lt;p&gt;To bring you in the mood let’s sketch the environment, I’ve been doing a lot of Scala, some Haskell and Rust before I started working on the thesis. The Salve game was written in Java, so guess what style I used for this typical Object Oriented programming language? Pure Functional! By this I mean that aside from local scope mutations, the entire structure was immutable. Take for example source block &lt;a href=&quot;java:immutable&quot;&gt;java:immutable&lt;/a&gt;. We need to make the collections private because Java collections are mutable. There is no need for the &lt;code class=&quot;verbatim&quot;&gt;name&lt;/code&gt; and &lt;code class=&quot;verbatim&quot;&gt;scene&lt;/code&gt; attributes to become private because they are already immutable, so they will never change. We made &lt;code class=&quot;verbatim&quot;&gt;hash_value&lt;/code&gt; private, even though it’s immutable, because code shouldn’t depend on that. This is a core principal of the code base, make everything immutable even though Java doesn’t really cooperate with that.&lt;/p&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
Immutable example
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;java:immutable&quot;&gt;&lt;pre class=&quot;sourceCode java&quot;&gt;&lt;code class=&quot;sourceCode java&quot;&gt;&lt;span id=&quot;java:immutable-1&quot;&gt;&lt;a href=&quot;#java:immutable-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;@Immutable&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:immutable-2&quot;&gt;&lt;a href=&quot;#java:immutable-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; Symbol &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:immutable-3&quot;&gt;&lt;a href=&quot;#java:immutable-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt; name&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;// filename&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:immutable-4&quot;&gt;&lt;a href=&quot;#java:immutable-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; Scene scene&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:immutable-5&quot;&gt;&lt;a href=&quot;#java:immutable-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;java:immutable-6&quot;&gt;&lt;a href=&quot;#java:immutable-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; literals&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:immutable-7&quot;&gt;&lt;a href=&quot;#java:immutable-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;TemplateAttribute&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; requiredTemplateVars&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:immutable-8&quot;&gt;&lt;a href=&quot;#java:immutable-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;java:immutable-9&quot;&gt;&lt;a href=&quot;#java:immutable-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; hash_value&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:immutable-10&quot;&gt;&lt;a href=&quot;#java:immutable-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:immutable-11&quot;&gt;&lt;a href=&quot;#java:immutable-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Ironically enough I undo this with the builder pattern in the unit tests. The issue is that immutability in Java is quite verbose to do, and I wanted a nice api to setup my the current dialogue on which I wanted to test the functions.&lt;/p&gt;
&lt;p&gt;I also wanted to have a good api for modeling the scenario from java code in the unit tests, and especially for this one I think I’ve succeeded (see figure &lt;a href=&quot;java:testapi&quot;&gt;java:testapi&lt;/a&gt;). We either connect up with any actor, or a restricted actor, however as you may see the result of these functions both go trough the same method connect. We do this by using an &lt;code class=&quot;verbatim&quot;&gt;Either&lt;/code&gt; type, which allows us to treat the same information kind off similarly for a while, and eventually on the right place we treat the cases separately. It’s kind off a delayed if statement. We can see the expansion of the if statement in figure &lt;a href=&quot;java:test:either&quot;&gt;java:test:either&lt;/a&gt;, this happens with help of the fold method, which receives a lambda per either path. Of course there are other ways to do this&lt;a href=&quot;#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;, but at the time of writing, I thought this was a really neat construct, because it’s precise and terse. I’m not sure if it’s a good or bad practice, but I think it &lt;em&gt;looks&lt;/em&gt; interesting.&lt;/p&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
API usage of creating in memory scenario
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;java:testapi&quot;&gt;&lt;pre class=&quot;sourceCode java&quot;&gt;&lt;code class=&quot;sourceCode java&quot;&gt;&lt;span id=&quot;java:testapi-1&quot;&gt;&lt;a href=&quot;#java:testapi-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; MockBelievesFactory &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-2&quot;&gt;&lt;a href=&quot;#java:testapi-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-3&quot;&gt;&lt;a href=&quot;#java:testapi-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt; hellos &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;hellos&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-4&quot;&gt;&lt;a href=&quot;#java:testapi-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt; whyhere &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;whyhere&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-5&quot;&gt;&lt;a href=&quot;#java:testapi-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt; maybeimsick &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;maybeimsick&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-6&quot;&gt;&lt;a href=&quot;#java:testapi-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt; ilikevistingyou &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;likevisitingyou&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-7&quot;&gt;&lt;a href=&quot;#java:testapi-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-8&quot;&gt;&lt;a href=&quot;#java:testapi-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt; needmedicine&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;needmedicine&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-9&quot;&gt;&lt;a href=&quot;#java:testapi-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt; imthedoctor&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;imthedoctor&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-10&quot;&gt;&lt;a href=&quot;#java:testapi-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-11&quot;&gt;&lt;a href=&quot;#java:testapi-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; Believes &lt;span class=&quot;fu&quot;&gt;createTestBelieves&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(){&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-12&quot;&gt;&lt;a href=&quot;#java:testapi-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;fu&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;hellos&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-13&quot;&gt;&lt;a href=&quot;#java:testapi-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;fu&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;whyhere&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Angry&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-14&quot;&gt;&lt;a href=&quot;#java:testapi-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;fu&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;hellos&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Happy&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-15&quot;&gt;&lt;a href=&quot;#java:testapi-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;fu&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;needmedicine&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Persuading&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Scary&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-16&quot;&gt;&lt;a href=&quot;#java:testapi-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-17&quot;&gt;&lt;a href=&quot;#java:testapi-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;fu&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;whyhere&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-18&quot;&gt;&lt;a href=&quot;#java:testapi-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;fu&quot;&gt;restricted&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;needmedicine&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; actor_patient&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Enlightening&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-19&quot;&gt;&lt;a href=&quot;#java:testapi-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;fu&quot;&gt;restricted&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;imthedoctor&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; actor_doctor&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Angry&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-20&quot;&gt;&lt;a href=&quot;#java:testapi-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;fu&quot;&gt;restricted&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;maybeimsick&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; actor_patient&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Angry&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-21&quot;&gt;&lt;a href=&quot;#java:testapi-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;fu&quot;&gt;restricted&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;ilikevistingyou&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; actor_patient&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;Happy&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-22&quot;&gt;&lt;a href=&quot;#java:testapi-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-23&quot;&gt;&lt;a href=&quot;#java:testapi-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-24&quot;&gt;&lt;a href=&quot;#java:testapi-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-25&quot;&gt;&lt;a href=&quot;#java:testapi-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:testapi-26&quot;&gt;&lt;a href=&quot;#java:testapi-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
API implementation with either types
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;java:test:either&quot;&gt;&lt;pre class=&quot;sourceCode java&quot;&gt;&lt;code class=&quot;sourceCode java&quot;&gt;&lt;span id=&quot;java:test:either-1&quot;&gt;&lt;a href=&quot;#java:test:either-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; MockBelievesFactory &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-2&quot;&gt;&lt;a href=&quot;#java:test:either-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;at&quot;&gt;@SafeVarargs&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-3&quot;&gt;&lt;a href=&quot;#java:test:either-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-4&quot;&gt;&lt;a href=&quot;#java:test:either-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt; one&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-5&quot;&gt;&lt;a href=&quot;#java:test:either-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        Either&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-6&quot;&gt;&lt;a href=&quot;#java:test:either-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            Pair&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; PerlocutionaryValueSet&lt;span class=&quot;op&quot;&gt;&amp;gt;,&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;java:test:either-7&quot;&gt;&lt;a href=&quot;#java:test:either-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            Triplet&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; Actor&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; PerlocutionaryValueSet&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-8&quot;&gt;&lt;a href=&quot;#java:test:either-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;...&lt;/span&gt; values&lt;/span&gt;
&lt;span id=&quot;java:test:either-9&quot;&gt;&lt;a href=&quot;#java:test:either-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-10&quot;&gt;&lt;a href=&quot;#java:test:either-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;bu&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; connections &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;createConnections&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;values&lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-11&quot;&gt;&lt;a href=&quot;#java:test:either-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;fu&quot;&gt;setconnect&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;one&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; connections&lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-12&quot;&gt;&lt;a href=&quot;#java:test:either-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-13&quot;&gt;&lt;a href=&quot;#java:test:either-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-14&quot;&gt;&lt;a href=&quot;#java:test:either-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;at&quot;&gt;@SafeVarargs&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-15&quot;&gt;&lt;a href=&quot;#java:test:either-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;createConnections&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-16&quot;&gt;&lt;a href=&quot;#java:test:either-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        Either&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-17&quot;&gt;&lt;a href=&quot;#java:test:either-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            Pair&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; PerlocutionaryValueSet&lt;span class=&quot;op&quot;&gt;&amp;gt;,&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;java:test:either-18&quot;&gt;&lt;a href=&quot;#java:test:either-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            Triplet&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; Actor&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; PerlocutionaryValueSet&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-19&quot;&gt;&lt;a href=&quot;#java:test:either-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;...&lt;/span&gt; values&lt;/span&gt;
&lt;span id=&quot;java:test:either-20&quot;&gt;&lt;a href=&quot;#java:test:either-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-21&quot;&gt;&lt;a href=&quot;#java:test:either-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;Arrays&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;asList&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;values&lt;span class=&quot;op&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;tupple &lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-22&quot;&gt;&lt;a href=&quot;#java:test:either-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            tupple&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;fold&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-23&quot;&gt;&lt;a href=&quot;#java:test:either-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                pair &lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-24&quot;&gt;&lt;a href=&quot;#java:test:either-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;fu&quot;&gt;createConnection&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;pair&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;getValue0&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(),&lt;/span&gt; actor_any&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; pair&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;getValue1&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;()),&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-25&quot;&gt;&lt;a href=&quot;#java:test:either-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-26&quot;&gt;&lt;a href=&quot;#java:test:either-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                tripple &lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-27&quot;&gt;&lt;a href=&quot;#java:test:either-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;fu&quot;&gt;createConnection&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;tripple&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;getValue0&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(),&lt;/span&gt; tripple&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;getValue1&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(),&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;java:test:either-28&quot;&gt;&lt;a href=&quot;#java:test:either-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  tripple&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;getValue2&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-29&quot;&gt;&lt;a href=&quot;#java:test:either-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-30&quot;&gt;&lt;a href=&quot;#java:test:either-30&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;Collectors&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;toSet&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-31&quot;&gt;&lt;a href=&quot;#java:test:either-31&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:test:either-32&quot;&gt;&lt;a href=&quot;#java:test:either-32&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;fancy-tree-traversal&quot;&gt;Fancy tree traversal&lt;/h2&gt;
&lt;p&gt;In many ways this structure was the core of deliberation. The Jungian functions needed to make modifications to this structure, but I wanted it to be immutable.&lt;/p&gt;
&lt;p&gt;To modify an immutable tree we need to pass a function down to the node where we want to do the modification and then apply it, once this is done we can go back up the tree with the new modified tree as leaf passing as a result the new tree. The function that does this is &lt;code class=&quot;verbatim&quot;&gt;withPrefferdIfAtHeight&lt;/code&gt; in source block &lt;a href=&quot;java:dialoguetree&quot;&gt;java:dialoguetree&lt;/a&gt;. In this example we make heavy use of continuations to make a really terse tree traversal (at least for java). The &lt;code class=&quot;verbatim&quot;&gt;copyWithAboveLeftMostLeaf&lt;/code&gt; and &lt;code class=&quot;verbatim&quot;&gt;copyWithStartAtUntilLeaf&lt;/code&gt; are the main clients of this function, however they just fill in the continuations.&lt;/p&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
Tree recursion with continuations
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;java:dialoguetree&quot;&gt;&lt;pre class=&quot;sourceCode java&quot;&gt;&lt;code class=&quot;sourceCode java&quot;&gt;&lt;span id=&quot;java:dialoguetree-1&quot;&gt;&lt;a href=&quot;#java:dialoguetree-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;@Immutable&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-2&quot;&gt;&lt;a href=&quot;#java:dialoguetree-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; DialogueTree &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-3&quot;&gt;&lt;a href=&quot;#java:dialoguetree-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; Utterance utterance&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-4&quot;&gt;&lt;a href=&quot;#java:dialoguetree-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;Connection&lt;/span&gt; connectionUsed&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-5&quot;&gt;&lt;a href=&quot;#java:dialoguetree-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;DialogueTree&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; options&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-6&quot;&gt;&lt;a href=&quot;#java:dialoguetree-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-7&quot;&gt;&lt;a href=&quot;#java:dialoguetree-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;co&quot;&gt;/**&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-8&quot;&gt;&lt;a href=&quot;#java:dialoguetree-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;     &lt;span class=&quot;co&quot;&gt;*&lt;/span&gt; If we have a preffered&lt;span class=&quot;co&quot;&gt;,&lt;/span&gt; execute withPrefferd on it&lt;span class=&quot;co&quot;&gt;,&lt;/span&gt; If we don&lt;span class=&quot;co&quot;&gt;&amp;#39;&lt;/span&gt;t have&lt;span class=&quot;co&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-9&quot;&gt;&lt;a href=&quot;#java:dialoguetree-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;     &lt;span class=&quot;co&quot;&gt;*&lt;/span&gt; execute ifNoPrefferedWithThis on the current object&lt;span class=&quot;co&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-10&quot;&gt;&lt;a href=&quot;#java:dialoguetree-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;     &lt;span class=&quot;co&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-11&quot;&gt;&lt;a href=&quot;#java:dialoguetree-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;private&lt;/span&gt; DialogueTree &lt;span class=&quot;fu&quot;&gt;mapPreffered&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-12&quot;&gt;&lt;a href=&quot;#java:dialoguetree-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        Function&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;DialogueTree&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; DialogueTree&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; withPreffered&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-13&quot;&gt;&lt;a href=&quot;#java:dialoguetree-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        Function&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;DialogueTree&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; DialogueTree&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; ifNoPreferedWithThis&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-14&quot;&gt;&lt;a href=&quot;#java:dialoguetree-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-15&quot;&gt;&lt;a href=&quot;#java:dialoguetree-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; Optional&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;DialogueTree&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prefferedOption &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;getOptions&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;findFirst&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-16&quot;&gt;&lt;a href=&quot;#java:dialoguetree-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; prefferedOption&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;preffered &lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-17&quot;&gt;&lt;a href=&quot;#java:dialoguetree-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;DialogueTree&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; options &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-18&quot;&gt;&lt;a href=&quot;#java:dialoguetree-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;fu&quot;&gt;getOptions&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;Collectors&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;toList&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-19&quot;&gt;&lt;a href=&quot;#java:dialoguetree-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            options&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; withPreffered&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;preffered&lt;span class=&quot;op&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;// 0 being preffered&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-20&quot;&gt;&lt;a href=&quot;#java:dialoguetree-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;replaceOptions&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;options&lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-21&quot;&gt;&lt;a href=&quot;#java:dialoguetree-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-22&quot;&gt;&lt;a href=&quot;#java:dialoguetree-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;orElse&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;co&quot;&gt;// there is no first option&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-23&quot;&gt;&lt;a href=&quot;#java:dialoguetree-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            ifNoPreferedWithThis&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-24&quot;&gt;&lt;a href=&quot;#java:dialoguetree-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-25&quot;&gt;&lt;a href=&quot;#java:dialoguetree-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-26&quot;&gt;&lt;a href=&quot;#java:dialoguetree-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-27&quot;&gt;&lt;a href=&quot;#java:dialoguetree-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;co&quot;&gt;/**&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-28&quot;&gt;&lt;a href=&quot;#java:dialoguetree-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;     &lt;span class=&quot;co&quot;&gt;*&lt;/span&gt; Generalization of &lt;span class=&quot;co&quot;&gt;&amp;#39;&lt;/span&gt;copyWithStartAtUntilLeaf&lt;span class=&quot;co&quot;&gt;&amp;#39;&lt;/span&gt; and&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-29&quot;&gt;&lt;a href=&quot;#java:dialoguetree-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;     &lt;span class=&quot;co&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;&amp;#39;&lt;/span&gt;copyWithAboveLeftMostLeaf&lt;span class=&quot;co&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-30&quot;&gt;&lt;a href=&quot;#java:dialoguetree-30&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;     &lt;span class=&quot;co&quot;&gt;*&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-31&quot;&gt;&lt;a href=&quot;#java:dialoguetree-31&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;     &lt;span class=&quot;co&quot;&gt;*&lt;/span&gt; You could very easily traverse the tree with this if you attach whenNot&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-32&quot;&gt;&lt;a href=&quot;#java:dialoguetree-32&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;     &lt;span class=&quot;co&quot;&gt;*&lt;/span&gt; into the called function of the argument dialogueTree&lt;span class=&quot;co&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-33&quot;&gt;&lt;a href=&quot;#java:dialoguetree-33&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;     &lt;span class=&quot;co&quot;&gt;*&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-34&quot;&gt;&lt;a href=&quot;#java:dialoguetree-34&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;     &lt;span class=&quot;co&quot;&gt;*&lt;/span&gt; Whenat will always be exeucted on the leaf&lt;span class=&quot;co&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-35&quot;&gt;&lt;a href=&quot;#java:dialoguetree-35&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;     &lt;span class=&quot;co&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-36&quot;&gt;&lt;a href=&quot;#java:dialoguetree-36&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;private&lt;/span&gt; DialogueTree &lt;span class=&quot;fu&quot;&gt;withPrefferdIfAtHeight&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-37&quot;&gt;&lt;a href=&quot;#java:dialoguetree-37&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; height&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-38&quot;&gt;&lt;a href=&quot;#java:dialoguetree-38&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        Function&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;DialogueTree&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; DialogueTree&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; whenNot&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-39&quot;&gt;&lt;a href=&quot;#java:dialoguetree-39&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        Function&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;DialogueTree&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; DialogueTree&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; whenAt&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-40&quot;&gt;&lt;a href=&quot;#java:dialoguetree-40&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-41&quot;&gt;&lt;a href=&quot;#java:dialoguetree-41&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;thisIsAtHeight&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;height&lt;span class=&quot;op&quot;&gt;)){&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;// in practice equal, but we just don&amp;#39;t want stackoverflows&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-42&quot;&gt;&lt;a href=&quot;#java:dialoguetree-42&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;co&quot;&gt;// note return&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-43&quot;&gt;&lt;a href=&quot;#java:dialoguetree-43&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; whenAt&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-44&quot;&gt;&lt;a href=&quot;#java:dialoguetree-44&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-45&quot;&gt;&lt;a href=&quot;#java:dialoguetree-45&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;co&quot;&gt;// we execute whenNot on preffered, because if we were at height the&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-46&quot;&gt;&lt;a href=&quot;#java:dialoguetree-46&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;co&quot;&gt;// previous condition woudl&amp;#39;ve been true&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-47&quot;&gt;&lt;a href=&quot;#java:dialoguetree-47&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;co&quot;&gt;// however if there is no prefered we are at leaf level.&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-48&quot;&gt;&lt;a href=&quot;#java:dialoguetree-48&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;mapPreffered&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;whenNot&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; whenAt&lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-49&quot;&gt;&lt;a href=&quot;#java:dialoguetree-49&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-50&quot;&gt;&lt;a href=&quot;#java:dialoguetree-50&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-51&quot;&gt;&lt;a href=&quot;#java:dialoguetree-51&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;co&quot;&gt;/**&lt;/span&gt; go down until height&lt;span class=&quot;co&quot;&gt;,&lt;/span&gt; then keep applying function until leaf &lt;span class=&quot;co&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-52&quot;&gt;&lt;a href=&quot;#java:dialoguetree-52&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; DialogueTree &lt;span class=&quot;fu&quot;&gt;copyWithStartAtUntilLeaf&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-53&quot;&gt;&lt;a href=&quot;#java:dialoguetree-53&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; height&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-54&quot;&gt;&lt;a href=&quot;#java:dialoguetree-54&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        Function&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;DialogueTree&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; DialogueTree&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; function&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-55&quot;&gt;&lt;a href=&quot;#java:dialoguetree-55&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-56&quot;&gt;&lt;a href=&quot;#java:dialoguetree-56&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;height &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt; leaf_height&lt;span class=&quot;op&quot;&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-57&quot;&gt;&lt;a href=&quot;#java:dialoguetree-57&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-58&quot;&gt;&lt;a href=&quot;#java:dialoguetree-58&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-59&quot;&gt;&lt;a href=&quot;#java:dialoguetree-59&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;withPrefferdIfAtHeight&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-60&quot;&gt;&lt;a href=&quot;#java:dialoguetree-60&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            height&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-61&quot;&gt;&lt;a href=&quot;#java:dialoguetree-61&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            tree &lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt; tree&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;copyWithStartAtUntilLeaf&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;height&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;function&lt;span class=&quot;op&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-62&quot;&gt;&lt;a href=&quot;#java:dialoguetree-62&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            tree &lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-63&quot;&gt;&lt;a href=&quot;#java:dialoguetree-63&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; DialogueTree result &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; function&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;tree&lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-64&quot;&gt;&lt;a href=&quot;#java:dialoguetree-64&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; result&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;mapPreffered&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-65&quot;&gt;&lt;a href=&quot;#java:dialoguetree-65&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                    prefferd &lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt; prefferd&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;copyWithStartAtUntilLeaf&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-66&quot;&gt;&lt;a href=&quot;#java:dialoguetree-66&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                        height&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; function&lt;span class=&quot;op&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-67&quot;&gt;&lt;a href=&quot;#java:dialoguetree-67&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                    Function&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;identity&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-68&quot;&gt;&lt;a href=&quot;#java:dialoguetree-68&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-69&quot;&gt;&lt;a href=&quot;#java:dialoguetree-69&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-70&quot;&gt;&lt;a href=&quot;#java:dialoguetree-70&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-71&quot;&gt;&lt;a href=&quot;#java:dialoguetree-71&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-72&quot;&gt;&lt;a href=&quot;#java:dialoguetree-72&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-73&quot;&gt;&lt;a href=&quot;#java:dialoguetree-73&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;co&quot;&gt;/**&lt;/span&gt; A more generalized form that can opperate on any height &lt;span class=&quot;co&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-74&quot;&gt;&lt;a href=&quot;#java:dialoguetree-74&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; DialogueTree &lt;span class=&quot;fu&quot;&gt;copyWithAboveLeftMostLeaf&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-75&quot;&gt;&lt;a href=&quot;#java:dialoguetree-75&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; height&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-76&quot;&gt;&lt;a href=&quot;#java:dialoguetree-76&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        Function&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;DialogueTree&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; DialogueTree&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; function&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-77&quot;&gt;&lt;a href=&quot;#java:dialoguetree-77&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-78&quot;&gt;&lt;a href=&quot;#java:dialoguetree-78&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;withPrefferdIfAtHeight&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-79&quot;&gt;&lt;a href=&quot;#java:dialoguetree-79&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            height&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-80&quot;&gt;&lt;a href=&quot;#java:dialoguetree-80&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            tree &lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt; tree&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;copyWithAboveLeftMostLeaf&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;height&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;function&lt;span class=&quot;op&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-81&quot;&gt;&lt;a href=&quot;#java:dialoguetree-81&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            function&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-82&quot;&gt;&lt;a href=&quot;#java:dialoguetree-82&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-83&quot;&gt;&lt;a href=&quot;#java:dialoguetree-83&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-84&quot;&gt;&lt;a href=&quot;#java:dialoguetree-84&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:dialoguetree-85&quot;&gt;&lt;a href=&quot;#java:dialoguetree-85&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The tree traversal is extensively tested upon correctness by the unit tests aimed at the Jungian functions. This helped me a lot with coming with this design in the first place, because the unit tests would tell me if I did something different. I thought this example was interesting because of the use in continuations, I’ve never really done tree traversal like this aside from &lt;a href=&quot;https://github.com/bitemyapp/learnhaskell&quot;&gt;studying&lt;/a&gt; &lt;a href=&quot;https://www.seas.upenn.edu/%7Ecis194/spring13/lectures.html&quot;&gt;Haskell&lt;/a&gt;. I did find it really difficult to think of appropriate names for the continuation functions because they’re so abstract. At this point I also started to wonder, are these kind off levels of abstractions even useful? I mean dialogue tree traversal became in my case really easy , I would say yes. This only happened after I implemented all the Jungian Functions and did a refactor round with the unit tests in place came I up with this design. I would imagine most code bases not really wanting to go this far.&lt;/p&gt;
&lt;h2 id=&quot;graph-duality&quot;&gt;Graph duality&lt;/h2&gt;
&lt;p&gt;This piece of code lingers on the point of madness..&lt;/p&gt;
&lt;p&gt;Chatbot works modularized pattern matching called scenes. When a scene is active we only match upon patterns of symbols in that scene, if there are no such patterns we look at the connections going out to neighbouring scenes and match upon the patterns of the symbols leading to those.&lt;/p&gt;
&lt;p&gt;To do this we have two pattern databases, the first one for within the scene and the second going out of the scene. The entire code that construct these databases can be seen in source block &lt;a href=&quot;java:patternprocessing&quot;&gt;java:patternprocessing&lt;/a&gt;. We can see the first database be constructed in &lt;code class=&quot;verbatim&quot;&gt;createSceneContained&lt;/code&gt; function. It just groups patterns based up their sybmols’ scenes. The patterns then point to their respective symbol with help of &lt;code class=&quot;verbatim&quot;&gt;PatternSymbol&lt;/code&gt; structure that is setup in the &lt;code class=&quot;verbatim&quot;&gt;flatten&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;The second database is much more difficult. We need to go trough all the &lt;code class=&quot;verbatim&quot;&gt;PatternSymbols&lt;/code&gt; and see if they came from any connections that transit scene, this is what the &lt;code class=&quot;verbatim&quot;&gt;filter&lt;/code&gt; function does in the stream. To figure out in what scene to put this pattern symbol we create a different kind of connection database. This connection database has all the connections point in the opposite direction, we call this the &lt;em&gt;dual&lt;/em&gt;. This idea just use a dual came from my geometric algorithm course, where they significantly reduced the complexity of an algorithm by converting points in lines and vice versa. The dual in this case does something similar, because if you call it twice you end up with the same structure.&lt;/p&gt;
&lt;p&gt;The final step in both cases is constructing the hash map, this is used in a various places, therefore it was moved to the functions class.&lt;/p&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
Constructing pattern databases, core functions
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;java:patternprocessing&quot;&gt;&lt;pre class=&quot;sourceCode java&quot;&gt;&lt;code class=&quot;sourceCode java&quot;&gt;&lt;span id=&quot;java:patternprocessing-1&quot;&gt;&lt;a href=&quot;#java:patternprocessing-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; PatternProcessing &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-2&quot;&gt;&lt;a href=&quot;#java:patternprocessing-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;static&lt;/span&gt; PatternDatabase &lt;span class=&quot;fu&quot;&gt;createSceneContained&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-3&quot;&gt;&lt;a href=&quot;#java:patternprocessing-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;bu&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;Symbol&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;Pattern&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; from&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-4&quot;&gt;&lt;a href=&quot;#java:patternprocessing-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-5&quot;&gt;&lt;a href=&quot;#java:patternprocessing-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;PatternDatabase&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-6&quot;&gt;&lt;a href=&quot;#java:patternprocessing-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            Functions&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;streamToHashMapSet&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-7&quot;&gt;&lt;a href=&quot;#java:patternprocessing-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;fu&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;from&lt;span class=&quot;op&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-8&quot;&gt;&lt;a href=&quot;#java:patternprocessing-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                key &lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt; key&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;scene&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-9&quot;&gt;&lt;a href=&quot;#java:patternprocessing-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                Function&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;identity&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-10&quot;&gt;&lt;a href=&quot;#java:patternprocessing-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-11&quot;&gt;&lt;a href=&quot;#java:patternprocessing-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-12&quot;&gt;&lt;a href=&quot;#java:patternprocessing-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-13&quot;&gt;&lt;a href=&quot;#java:patternprocessing-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-14&quot;&gt;&lt;a href=&quot;#java:patternprocessing-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;static&lt;/span&gt; PatternDatabase &lt;span class=&quot;fu&quot;&gt;createSceneNextTo&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-15&quot;&gt;&lt;a href=&quot;#java:patternprocessing-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;bu&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;Symbol&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;Pattern&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; from&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-16&quot;&gt;&lt;a href=&quot;#java:patternprocessing-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ConnectionDatabase db&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-17&quot;&gt;&lt;a href=&quot;#java:patternprocessing-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-18&quot;&gt;&lt;a href=&quot;#java:patternprocessing-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ConnectionDatabase dual &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; db&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;createDual&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-19&quot;&gt;&lt;a href=&quot;#java:patternprocessing-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;PatternDatabase&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-20&quot;&gt;&lt;a href=&quot;#java:patternprocessing-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            Functions&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;streamToHashMapSet&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-21&quot;&gt;&lt;a href=&quot;#java:patternprocessing-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;fu&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;from&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-22&quot;&gt;&lt;a href=&quot;#java:patternprocessing-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;flatMap&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;patternSymbol &lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-23&quot;&gt;&lt;a href=&quot;#java:patternprocessing-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                    dual&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;getConnections&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;patternSymbol&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-24&quot;&gt;&lt;a href=&quot;#java:patternprocessing-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                        &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;connection &lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-25&quot;&gt;&lt;a href=&quot;#java:patternprocessing-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                            &lt;span class=&quot;op&quot;&gt;!&lt;/span&gt;connection&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;scene&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;equals&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-26&quot;&gt;&lt;a href=&quot;#java:patternprocessing-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                                patternSymbol&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;scene&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-27&quot;&gt;&lt;a href=&quot;#java:patternprocessing-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                            &lt;span class=&quot;op&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-28&quot;&gt;&lt;a href=&quot;#java:patternprocessing-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                        &lt;span class=&quot;op&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-29&quot;&gt;&lt;a href=&quot;#java:patternprocessing-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                        &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;connection &lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-30&quot;&gt;&lt;a href=&quot;#java:patternprocessing-30&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                            &lt;span class=&quot;kw&quot;&gt;new&lt;/span&gt; Pair&lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;(&lt;/span&gt;connection&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;scene&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; patternSymbol&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-31&quot;&gt;&lt;a href=&quot;#java:patternprocessing-31&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                        &lt;span class=&quot;op&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-32&quot;&gt;&lt;a href=&quot;#java:patternprocessing-32&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-33&quot;&gt;&lt;a href=&quot;#java:patternprocessing-33&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                Pair&lt;span class=&quot;op&quot;&gt;::&lt;/span&gt;getValue0&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-34&quot;&gt;&lt;a href=&quot;#java:patternprocessing-34&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                Pair&lt;span class=&quot;op&quot;&gt;::&lt;/span&gt;getValue1&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-35&quot;&gt;&lt;a href=&quot;#java:patternprocessing-35&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-36&quot;&gt;&lt;a href=&quot;#java:patternprocessing-36&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-37&quot;&gt;&lt;a href=&quot;#java:patternprocessing-37&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-38&quot;&gt;&lt;a href=&quot;#java:patternprocessing-38&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-39&quot;&gt;&lt;a href=&quot;#java:patternprocessing-39&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;static&lt;/span&gt; Stream&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;PatternSymbol&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;Symbol&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;Pattern&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; from&lt;span class=&quot;op&quot;&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-40&quot;&gt;&lt;a href=&quot;#java:patternprocessing-40&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; from&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;entrySet&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-41&quot;&gt;&lt;a href=&quot;#java:patternprocessing-41&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-42&quot;&gt;&lt;a href=&quot;#java:patternprocessing-42&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;flatMap&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;entry &lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-43&quot;&gt;&lt;a href=&quot;#java:patternprocessing-43&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                entry&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-44&quot;&gt;&lt;a href=&quot;#java:patternprocessing-44&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                    pattern &lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;PatternSymbol&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;pattern&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; entry&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;getKey&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-45&quot;&gt;&lt;a href=&quot;#java:patternprocessing-45&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-46&quot;&gt;&lt;a href=&quot;#java:patternprocessing-46&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-47&quot;&gt;&lt;a href=&quot;#java:patternprocessing-47&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:patternprocessing-48&quot;&gt;&lt;a href=&quot;#java:patternprocessing-48&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I really wanted to show the dual idea somewhere because I know this is a hard problem to solve, but it didn’t take a lot of effort because of the dual idea. Not sure how readable this is though, this is a problem I have more often with functional programming.. How do you know what is a good or bad pattern? I guess I just need more experience or talk with other people about this.&lt;/p&gt;
&lt;h2 id=&quot;lazy-hashing&quot;&gt;Lazy hashing&lt;/h2&gt;
&lt;p&gt;The only reason I’m discussing this is because I worked with Java (Scala does the hashing stuff for you in case classes), and in some situations you did not want to calculate the hash code eagerly because the model object contained a collection (which could be a lot of work). I modified this &lt;a href=&quot;https://stackoverflow.com/questions/29132884/lazy-field-initialization-with-lambdas&quot;&gt;stack overflow&lt;/a&gt; to work for hashing resulting in the code seen in source block &lt;a href=&quot;java:lazyhash&quot;&gt;java:lazyhash&lt;/a&gt;. So what happens is as soon as the &lt;code class=&quot;verbatim&quot;&gt;hashCode&lt;/code&gt; function is called we calculate it, and then replace the supplier hash with a new lambda that just returns the result. Note that this will never change because the model object is immutable.&lt;/p&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
The lambda replaces itself with the result
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;java:lazyhash&quot;&gt;&lt;pre class=&quot;sourceCode java&quot;&gt;&lt;code class=&quot;sourceCode java&quot;&gt;&lt;span id=&quot;java:lazyhash-1&quot;&gt;&lt;a href=&quot;#java:lazyhash-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;@Immutable&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-2&quot;&gt;&lt;a href=&quot;#java:lazyhash-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; Utterance &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-3&quot;&gt;&lt;a href=&quot;#java:lazyhash-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; Informative informative&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-4&quot;&gt;&lt;a href=&quot;#java:lazyhash-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; Instant when&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;// immutable&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-5&quot;&gt;&lt;a href=&quot;#java:lazyhash-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; CapturedMatchDB capturedDB&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-6&quot;&gt;&lt;a href=&quot;#java:lazyhash-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; PerlocutionaryValueSet perlocutionaryValues&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-7&quot;&gt;&lt;a href=&quot;#java:lazyhash-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-8&quot;&gt;&lt;a href=&quot;#java:lazyhash-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;private&lt;/span&gt; Supplier&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; lazyHashValue&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-9&quot;&gt;&lt;a href=&quot;#java:lazyhash-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-10&quot;&gt;&lt;a href=&quot;#java:lazyhash-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Utterance&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;Informative informative&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; PerlocutionaryValueSet perlocutionaryValues&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; CapturedMatchDB capturedDB&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-11&quot;&gt;&lt;a href=&quot;#java:lazyhash-11&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;informative&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; informative&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-12&quot;&gt;&lt;a href=&quot;#java:lazyhash-12&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;capturedDB&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; capturedDB&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-13&quot;&gt;&lt;a href=&quot;#java:lazyhash-13&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;perlocutionaryValues&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; perlocutionaryValues&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-14&quot;&gt;&lt;a href=&quot;#java:lazyhash-14&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; Instant&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-15&quot;&gt;&lt;a href=&quot;#java:lazyhash-15&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-16&quot;&gt;&lt;a href=&quot;#java:lazyhash-16&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        lazyHashValue &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-17&quot;&gt;&lt;a href=&quot;#java:lazyhash-17&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;co&quot;&gt;// since the class is immutable and we don&amp;#39;t deal with collections,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-18&quot;&gt;&lt;a href=&quot;#java:lazyhash-18&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;co&quot;&gt;// we can calulate this now, if it every is required...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-19&quot;&gt;&lt;a href=&quot;#java:lazyhash-19&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;dt&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; hash_code &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-20&quot;&gt;&lt;a href=&quot;#java:lazyhash-20&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;dv&quot;&gt;311&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; informative&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;hashCode&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-21&quot;&gt;&lt;a href=&quot;#java:lazyhash-21&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;dv&quot;&gt;193&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;perlocutionaryValues&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;hashCode&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-22&quot;&gt;&lt;a href=&quot;#java:lazyhash-22&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;dv&quot;&gt;701&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; capturedDB&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;hashCode&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-23&quot;&gt;&lt;a href=&quot;#java:lazyhash-23&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            lazyHashValue &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;-&amp;gt;&lt;/span&gt; hash_code&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-24&quot;&gt;&lt;a href=&quot;#java:lazyhash-24&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; hash_code&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-25&quot;&gt;&lt;a href=&quot;#java:lazyhash-25&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-26&quot;&gt;&lt;a href=&quot;#java:lazyhash-26&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-27&quot;&gt;&lt;a href=&quot;#java:lazyhash-27&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-28&quot;&gt;&lt;a href=&quot;#java:lazyhash-28&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;at&quot;&gt;@Override&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-29&quot;&gt;&lt;a href=&quot;#java:lazyhash-29&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;hashCode&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(){&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-30&quot;&gt;&lt;a href=&quot;#java:lazyhash-30&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; lazyHashValue&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-31&quot;&gt;&lt;a href=&quot;#java:lazyhash-31&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-32&quot;&gt;&lt;a href=&quot;#java:lazyhash-32&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;java:lazyhash-33&quot;&gt;&lt;a href=&quot;#java:lazyhash-33&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h1 id=&quot;the-experience&quot;&gt;The experience&lt;/h1&gt;
&lt;p&gt;I specifically asked my teacher for getting a ‘practical’ assignment because I’m good at that. When he mentioned personality research I also opted into that, because I already knew a fair bit about MBTI. Finally, the personality as a process bit was all my teachers’ suggestion, but I really liked that idea.&lt;/p&gt;
&lt;h2 id=&quot;doing-research&quot;&gt;Doing research&lt;/h2&gt;
&lt;p&gt;When I started doing the thesis I was mostly on my own, my guiding teacher had left for Australia for 6 weeks, and I just started with what I think had to be done. I never had done before any research of this kind of scale so I just used common sense to decide what to do. However I made sure to keep my teacher up to date with weekly updates trough email.&lt;/p&gt;
&lt;p&gt;The researching part consisted of several parts. First of all, the personality research with which I started, this was just ploughing trough papers on my own. Then came analyzing the chatbot, this was quite fun because it was just reverse engineering some poorly written code, which is challenging but also rewarding (I always get the idea I learn to know the author better by studying his code). Finally I needed to develop a theory of Jung and Dialogue, this was done mostly with the Haskell notation and giving my own interpretations of the Jungian functions. Then I also developed a way of combining them.&lt;/p&gt;
&lt;p&gt;When my teacher came back I was mostly done with all of that. So he had a lot to catch-up with because I was writing my thesis while doing research. Even though I was thoroughly working for just six hours per day, he complemented me and said I had done a lot of work. I continued working just six hours per day.&lt;/p&gt;
&lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;/h2&gt;
&lt;p&gt;Once I was finished writing what I wanted to do in a functional design I started with the implementation. I quickly decided to &lt;strong&gt;not&lt;/strong&gt; use the ALICE bot. It was poorly written, with for example many global mutable variables, frantic use of public mutable attributes and all the things you shouldn’t do.&lt;/p&gt;
&lt;p&gt;In the thesis I justify moving to the new system by saying that AIML doesn’t offer the capability of providing choice, which is a much better reason that what made me look for alternatives in the first place. The first strike AIML got was by just being based upon XML, most programmers will know &lt;a href=&quot;http://wiki.c2.com/?XmlSucks&quot;&gt;XML sucks&lt;/a&gt; (usually, there are good cases for XML). The reason I was pushed initially started looking for an alternative was because I didn’t like the jury rigged combination of drools and AIML.&lt;/p&gt;
&lt;p&gt;What I did was a quick implementation of how I envisioned the chatbot that could co-exist beside XML. I showed this to my programming guiding teacher after about two weeks of hacking, and he recommended me to just dump the old implementation and go with whatever I was making. He also pushed me to use drools much more intensively rather than java, which resulted in some good changes such as the pattern matching code becoming a drools rule, and some changes I like less such as the personality order being in both a list and the next function.&lt;/p&gt;
&lt;h2 id=&quot;presentation&quot;&gt;Presentation&lt;/h2&gt;
&lt;p&gt;I had way to much time to prepare for the preparation. Partly because one of the faculty members got a disease. But also because the primary guiding teacher was a very busy man and I had a long thesis.&lt;/p&gt;
&lt;p&gt;I think I practiced the entire thing about 10 times in total. In the beginning I would often change the presentation after practicing but the presentation would become more final after each run. Each time I would be over time by a margin, however on presentation day itself I somehow managed to get exactly the right time. The difference probably is in stress level.&lt;/p&gt;
&lt;p&gt;I don’t remember giving the presentation, I know I stood there, said words, but I have barely any memories from the event. This usually happens to me when giving presentations, luckily my father filmed the entire thing. I was a little disappointed with the grade, but not too much, the criticism that I didn’t add much theory was fair. However I think I couldn’t do this much better because I just don’t know how to develop theoretic foundations. This is partly because of my software engineering background, whereas the second judge was mostly from a mathematical background.&lt;/p&gt;
&lt;p&gt;The questions I got were really quite though, firstly I was asked to describe precisely if a thinking function would be first in order, how would it still get to influence the result. The answer was that it just could inspect the result, because we have a two pass architecture, going deeper first. However because this is a very detailed question it took me a while to figure out what he meant by that. They also asked me about if the division between rational and irrational as action generation and sorting was a design decision, and yes it was. Then another question was about, can we extract the ‘communicate!’ game information from the GUI and encode it into the new game, what personality would the actor have in that game? I would say yes upon extraction (even automatic) but I didn’t know what personality because I didn’t study those dialogues (in fact I barely studied the communicate game). Finally a question was asked in which cases this would help doctors, I replied with the more emotional situations because it would be important to treat someone right under these cases.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;I would say that I liked doing my thesis as a whole. In fact I would say I enjoyed the entire master, but I do know that I’m not an academic, my initial hasty assumption of “head in the clouds” was quite correct. The very notion of just always trying to do stuff in new approaches bothers me, I would rather just solve real world problem, with old approaches if they work, and do new approaches only when the use case demands it.&lt;/p&gt;
&lt;p&gt;Then there is also the issue of neglecting to publish source code, I just think that is terrible for science as it creates a lot of double work and since I personally prefer digging around in source code I’m almost certain I work badly in academia. By which I mean it would just make me unhappy, I don’t get excited by writing large bodies of text to the point of perfection. I just want to get out what is on my mind, &lt;a href=&quot;https://en.wikipedia.org/wiki/Release_early,_release_often&quot;&gt;release early release often&lt;/a&gt; rather than peer reviewed based academic releases. I choose the bazaar &lt;span class=&quot;citation&quot; data-cites=&quot;raymond1999cathedral&quot;&gt;cite:raymond1999cathedral&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;bibliographystyle:unsrt bibliography:./files/2017/refs.bib&lt;/p&gt;
&lt;section id=&quot;footnotes&quot; class=&quot;footnotes footnotes-end-of-document&quot; role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;For example: let the any function also return the triplet but setting it to any actor&lt;a href=&quot;#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content>
  </entry>
  <entry>
    <title>Website changes</title>
    <link href="https://jappieklooster.nl/website-changes.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2017-06-30:/website-changes.html</id>
    <published>2017-06-30T00:00:00Z</published>
    <updated>2017-06-30T00:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="meta"/>
    <summary type="html">&lt;p&gt;I recently made a lot of changes to this website, they aren’t big changes but the devil is in the details. I made these mostly in support of writing about &lt;a href=&quot;https://jappieklooster.nl/thesis&quot;&gt;my thesis&lt;/a&gt; as a &lt;a href=&quot;./my-thesis.org&quot;&gt;blog post&lt;/a&gt;. I for example moved to SVG images because I recently fell in love&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;I recently made a lot of changes to this website, they aren’t big changes but the devil is in the details. I made these mostly in support of writing about &lt;a href=&quot;https://jappieklooster.nl/thesis&quot;&gt;my thesis&lt;/a&gt; as a &lt;a href=&quot;./my-thesis.org&quot;&gt;blog post&lt;/a&gt;. I for example moved to SVG images because I recently fell in love with Inkscape, however I wanted to ensure that compression was enabled for these because XML is so verbose. Which took me on a small NGINX adventure. Then I did various styling changes in light of my job hunt. I still think this theme is correct but I made it more ‘tight’. These were just tweaking with CSS, except for the desire to typeset like latex, which I’ll discuss in the end.&lt;/p&gt;
&lt;h1 id=&quot;org-export&quot;&gt;Org export&lt;/h1&gt;
&lt;p&gt;I wanted to have source code highlighting with &lt;a href=&quot;http://pygments.org/&quot;&gt;Pygments&lt;/a&gt;. Org mode export didn’t do any coloring for me, however I came upon &lt;a href=&quot;https://emacs.stackexchange.com/questions/32700/styling-source-code-blocks-with-pygments-css-in-org-mode-html-export-pelican&quot;&gt;this question&lt;/a&gt;. which sort of answered it for me, except for telling how to load the lisp files which I figured out by studying the GitHub. Then I modified the answer to include that so others don’t have magically know that. There were standard style sheets for syntax highlighting available for pygments, I chose my favorite: &lt;a href=&quot;https://github.com/richleland/pygments-css/blob/master/monokai.css&quot;&gt;monokai&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the org references I wanted to have numbered citations rather than names. &lt;a href=&quot;http://kitchingroup.cheme.cmu.edu/blog/2015/12/03/Exporting-numbered-citations-in-html-with-unsorted-numbered-bibliography/&quot;&gt;This article&lt;/a&gt; was invaluable to help with that. The issue I had with that code is that I called it &lt;code class=&quot;verbatim&quot;&gt;org-ref-unsrt-html-processor&lt;/code&gt;, but I was using a custom variant called &lt;code class=&quot;verbatim&quot;&gt;org-ref-unsrt-pelican-html-processor&lt;/code&gt;, because of the Pygments extension. Renaming that correctly made it work and cost me about 4 hours of my life. So you can just dump that code in you &lt;code class=&quot;verbatim&quot;&gt;config.el&lt;/code&gt; file, but be aware of giving it the right export name.&lt;/p&gt;
&lt;p&gt;The final thing I did was making SVG files export to &lt;code class=&quot;verbatim&quot;&gt;img&lt;/code&gt; tags rather than &lt;code class=&quot;verbatim&quot;&gt;object&lt;/code&gt; tags, because &lt;code class=&quot;verbatim&quot;&gt;object&lt;/code&gt; tags just work very poorly. (Once I published it I couldn’t get it to work at all). What I did was overwriting the image formatting function in elisp as can be seen in source block &lt;a href=&quot;elisp:fixsvg&quot;&gt;elisp:fixsvg&lt;/a&gt;. The only thing I did was remove the check upon SVG files, instead it’ll use the default path which is using an &lt;code class=&quot;verbatim&quot;&gt;img&lt;/code&gt; tag. I placed this after the &lt;code class=&quot;verbatim&quot;&gt;ox-html&lt;/code&gt; require so it got overwritten by all following code (including the deriving stuff.. apparently).&lt;/p&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
Elisp image override
&lt;/div&gt;
&lt;pre id=&quot;elisp:fixsvg&quot; class=&quot;elisp&quot;&gt;&lt;code&gt;(require &amp;#39;ox-html)
(defun org-html--format-image (source attributes info)
  &amp;quot;Fix org&amp;#39;s implementation, no check for svg files (object is deprecated at 
    this point and not trusted by most browsers)&amp;quot;
    (org-html-close-tag
     &amp;quot;img&amp;quot;
     (org-html--make-attribute-string
      (org-combine-plists
       (list :src source
             :alt (if (string-match-p &amp;quot;^ltxpng/&amp;quot; source)
                      (org-html-encode-plain-text
                       (org-find-text-property-in-string &amp;#39;org-latex-src source))
                    (file-name-nondirectory source)))
       attributes))
     info))
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I’m still very happy to work in org mode, in fact the evaluation of source blocks makes it a great combination with plant UML, which I then can export to SVG images. This makes it &lt;strong&gt;much&lt;/strong&gt; easier to describe ideas (being a visual thinker), and allows version control upon UML.&lt;/p&gt;
&lt;h1 id=&quot;nginx&quot;&gt;NGINX&lt;/h1&gt;
&lt;p&gt;I enabled gzip compression for a bunch of different file extensions, (note this is handled by your web server, so its a practically free speedup for your website). but I know for a fact the SVG images profited a lot form that. &lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-add-the-gzip-module-to-nginx-on-ubuntu-14-04&quot;&gt;This article&lt;/a&gt; explains how to do it for NGINX.&lt;/p&gt;
&lt;p&gt;I also &lt;a href=&quot;https://tools.pingdom.com/&quot;&gt;tested&lt;/a&gt; the speed and it told me to enable caching of the SVG files, this had me confused for a little while but it meant you should tell the browser clients that the resource will stay the same for a long time (reducing load on your server &lt;em&gt;and&lt;/em&gt; since networking is slow giving a speedup). &lt;a href=&quot;https://serverfault.com/questions/23157/setting-expires-headers-for-static-content-served-from-nginx&quot;&gt;This serverfault&lt;/a&gt; explains it for NGINX, I had another post but couldn’t find it back, that said to put it on a year however (365d). Since I’m not planning to change anything except the PDF’s my NGINX config now looks like source block &lt;a href=&quot;nginx:caching&quot;&gt;nginx:caching&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
Cache NGINX rules
&lt;/div&gt;
&lt;pre id=&quot;nginx:caching&quot; class=&quot;nginx&quot;&gt;&lt;code&gt;# browser caching 
location ~*  \.(jpg|jpeg|png|gif|ico|css|js|svg)$ { 
        expires 365d; 
        add_header Pragma public;
        add_header Cache-Control &amp;quot;public&amp;quot;;
} 

# pdf also cache, shorter because we want to update our resume frequently 
location ~*  \.(pdf)$ { 
        expires 30d; 
        add_header Pragma public;
        add_header Cache-Control &amp;quot;public&amp;quot;;
}  
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h1 id=&quot;typeset-like-latex&quot;&gt;Typeset like latex&lt;/h1&gt;
&lt;p&gt;If you’ve ever worked with latex files you may have noticed how the text is aligned. Normally (MS Word for example) this is in ragged mode, where one side is a straight line down and the other side is ‘ragged’. Latex type-sets with full justification but doesn’t varied spacing between the words. I wanted that on this website. Btw, I’m fully aware that only a select few people will even notice this, the important point is that &lt;strong&gt;I&lt;/strong&gt; will notice this.&lt;/p&gt;
&lt;p&gt;I basically went trough &lt;a href=&quot;http://webtypography.net/toc/&quot;&gt;this entire site&lt;/a&gt;, I recommend doing the same if you manage your own CSS for your website. However there were two important sections, the one that describes &lt;a href=&quot;http://webtypography.net/2.1.3&quot;&gt;ragged&lt;/a&gt;, and the one about &lt;a href=&quot;http://webtypography.net/2.4.1&quot;&gt;hypenation&lt;/a&gt;. They basically recommend &lt;strong&gt;against&lt;/strong&gt; trying to emulate latex. But me, being the arrogant little bastard I am, was like “This is my blog, don’t tell me what to do” and started experimenting. The result of which you can see in source block &lt;a href=&quot;src:sasstypeset&quot;&gt;src:sasstypeset&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;captioned-content&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;
Sass of typeset experimentation
&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;src:sasstypeset&quot;&gt;&lt;pre class=&quot;sourceCode sass&quot;&gt;&lt;code class=&quot;sourceCode sass&quot;&gt;&lt;span id=&quot;src:sasstypeset-1&quot;&gt;&lt;a href=&quot;#src:sasstypeset-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;p&lt;/span&gt;
&lt;span id=&quot;src:sasstypeset-2&quot;&gt;&lt;a href=&quot;#src:sasstypeset-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;text-align&lt;/span&gt;: &lt;span class=&quot;dv&quot;&gt;justify&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;src:sasstypeset-3&quot;&gt;&lt;a href=&quot;#src:sasstypeset-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;hyphens&lt;/span&gt;: &lt;span class=&quot;bu&quot;&gt;auto&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;src:sasstypeset-4&quot;&gt;&lt;a href=&quot;#src:sasstypeset-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;line-height&lt;/span&gt;: &lt;span class=&quot;dv&quot;&gt;1.3&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;src:sasstypeset-5&quot;&gt;&lt;a href=&quot;#src:sasstypeset-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    \&lt;span class=&quot;op&quot;&gt;+&lt;/span&gt;p&lt;/span&gt;
&lt;span id=&quot;src:sasstypeset-6&quot;&gt;&lt;a href=&quot;#src:sasstypeset-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;text-indent&lt;/span&gt;: &lt;span class=&quot;dv&quot;&gt;1.375&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;em&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;src:sasstypeset-7&quot;&gt;&lt;a href=&quot;#src:sasstypeset-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;src:sasstypeset-8&quot;&gt;&lt;a href=&quot;#src:sasstypeset-8&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;// display inline otherwise hypenation doesn&amp;#39;t work (normaly inline-block)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;src:sasstypeset-9&quot;&gt;&lt;a href=&quot;#src:sasstypeset-9&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;.entry-content&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;src:sasstypeset-10&quot;&gt;&lt;a href=&quot;#src:sasstypeset-10&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;display&lt;/span&gt;: &lt;span class=&quot;dv&quot;&gt;inline&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The key to having proper justification is &lt;code class=&quot;verbatim&quot;&gt;text-align: justify&lt;/code&gt; and &lt;code class=&quot;verbatim&quot;&gt;hypens: auto&lt;/code&gt;, do note that for auto hyphens you need to set your website language, they actually have made dictionaries per language, of where to place hyphens. Another issue that I had was that certain lines would have massive spacing in the words, after staring at that for several hours I noticed this only happened before inline links. I put those on display inline-block, which apparently means: no line breaks. Once I put that on display inline it looked practically perfect.&lt;/p&gt;
&lt;p&gt;There is some other stuff in that sass, such as doing text indent for succeeding paragraphs (rather than margins), which I think looks the ‘nicest’, but that’s just personal preference. There are various other techniques, for which I refer to the &lt;a href=&quot;http://webtypography.net/2.3.2&quot;&gt;expert website&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Endorsement</title>
    <link href="https://jappieklooster.nl/endorsement.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2017-06-28:/endorsement.html</id>
    <published>2017-06-28T00:00:00Z</published>
    <updated>2021-08-29T14:20:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="meta"/>
    <summary type="html">&lt;p&gt;A post I’ll periodicly update (no promises) of links I’ve found that are interesting, funny whatever. I guess its a &lt;del&gt;hall&lt;/del&gt; wall of fame of sorts except it has zero prestige. (well maybe some day it will). It also serves as a kindoff reminder of stuff I used to like.&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;A post I’ll periodicly update (no promises) of links I’ve found that are interesting, funny whatever. I guess its a &lt;del&gt;hall&lt;/del&gt; wall of fame of sorts except it has zero prestige. (well maybe some day it will). It also serves as a kindoff reminder of stuff I used to like.&lt;/p&gt;
&lt;h1 id=&quot;beauty&quot;&gt;Beauty&lt;/h1&gt;
&lt;h2 id=&quot;a-work-of-art&quot;&gt;A work of art&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://aphyr.com/posts/342-typing-the-technical-interview&quot;&gt;https://aphyr.com/posts/342-typing-the-technical-interview&lt;/a&gt; I’m envious if the writing style in that blog post. It weaves together some extremely advanced type level programming with a funny narrative. I hope that I could produce this kind of writing in the future too.&lt;/p&gt;
&lt;h2 id=&quot;wallpapers&quot;&gt;Wallpapers&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://www.erikjohanssonphoto.com/&quot;&gt;http://www.erikjohanssonphoto.com/&lt;/a&gt; I used several images as wallpapers from this guy, at the time I couldn’t pay him so I guess I repay him by giving him some realestate on my website.&lt;/p&gt;
&lt;h1 id=&quot;funny&quot;&gt;Funny&lt;/h1&gt;
&lt;h2 id=&quot;suicide-linux&quot;&gt;Suicide linux&lt;/h2&gt;
&lt;p&gt;I remember a script that would execute &lt;code class=&quot;verbatim&quot;&gt;rm -rf /&lt;/code&gt; if you’d type a command incorrectly, just to teach you to be precise. It was &lt;a href=&quot;https://qntm.org/suicide&quot;&gt;sucide linux&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’m not running that.&lt;/p&gt;
&lt;h1 id=&quot;interesting&quot;&gt;Interesting&lt;/h1&gt;
&lt;h2 id=&quot;suckless&quot;&gt;Suckless&lt;/h2&gt;
&lt;p&gt;It’s software that sucks slightly less. &lt;a href=&quot;http://suckless.org/&quot;&gt;http://suckless.org/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Amongst other things they have a irc client that works with fifo queues on the filesystem. It’s beautifull.&lt;/p&gt;
&lt;h2 id=&quot;tsoding&quot;&gt;Tsoding&lt;/h2&gt;
&lt;p&gt;A &lt;a href=&quot;https://www.twitch.tv/tsoding&quot;&gt;streamer&lt;/a&gt; who makes a show of programming. With the slogan ‘coding for fun’ he traverses the programming landscape from &lt;a href=&quot;https://github.com/tsoding/HyperNerd&quot;&gt;haskell&lt;/a&gt; to &lt;a href=&quot;https://github.com/tsoding/wassm&quot;&gt;assembly&lt;/a&gt; and from &lt;a href=&quot;https://github.com/tsoding/HyperNerd/blob/master/src/Markov.hs&quot;&gt;markov chains&lt;/a&gt; to &lt;a href=&quot;https://github.com/tsoding/grub-gamepad&quot;&gt;grub drivers&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;cgpgrey&quot;&gt;CGPGrey&lt;/h2&gt;
&lt;p&gt;A youtuber, although I’m linking to his &lt;a href=&quot;http://www.cgpgrey.com/&quot;&gt;website&lt;/a&gt;. He has some interesting videos (of which I know him), but his podcasts are quite good too.&lt;/p&gt;
&lt;h2 id=&quot;brady-haron&quot;&gt;Brady haron&lt;/h2&gt;
&lt;p&gt;Also a youtber, &lt;a href=&quot;http://www.bradyharan.com/&quot;&gt;his website&lt;/a&gt;. His numberphile channel is fun.&lt;/p&gt;
&lt;h2 id=&quot;how-computers-learn&quot;&gt;How computers learn&lt;/h2&gt;
&lt;p&gt;A back to basics overview of machine learning: &lt;a href=&quot;https://youtu.be/T1O3ikmTEdA?t=644&quot;&gt;https://youtu.be/T1O3ikmTEdA?t=644&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Even though I knew most stuff he talked about in the beginning, the talk later becomes more interesting since I didn’t follow machine learning that much.&lt;/p&gt;
&lt;h2 id=&quot;tech-blogs&quot;&gt;Tech blogs&lt;/h2&gt;
&lt;p&gt;At some point I wanted to read interesting soemthing interesting, I found these who look all very interesting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.acolyer.org/&quot;&gt;https://blog.acolyer.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://highscalability.com/&quot;&gt;http://highscalability.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As I grow older I prune this list more. Technology in isolation is boring.&lt;/p&gt;
&lt;h2 id=&quot;blogs&quot;&gt;Blogs&lt;/h2&gt;
&lt;p&gt;These people write well. I like reading about the day to day issues in random company or struggles in life.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://rachelbythebay.com/w/&quot;&gt;https://rachelbythebay.com/w/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sandymaguire.me/&quot;&gt;https://sandymaguire.me/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.paulgraham.com/articles.html&quot;&gt;http://www.paulgraham.com/articles.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;stratechery&quot;&gt;Stratechery&lt;/h2&gt;
&lt;p&gt;This guy is some kindoff analist I encountered on reddit (probably the /r/investing sub). He has some really interesting takes on tech companies and I learned a lot about buisness in general from just reading his blog. I especially liked his aggregration theory, makes me wonder if I could make one of those.. (probably not). &lt;a href=&quot;https://stratechery.com/&quot;&gt;https://stratechery.com/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;danluu&quot;&gt;danluu&lt;/h2&gt;
&lt;p&gt;I found one of his articles on reddit, and he has an interesting perspective (as moslty a hardware person). I was reading the article &lt;a href=&quot;https://danluu.com/wat/&quot;&gt;normalization of defiance&lt;/a&gt; which talks about how strange, shady or broken practices are born, and what one could do about them. Then I went to the index and it turns out there is a huge treasure trove of interesting articles on that blog.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://danluu.com/&quot;&gt;https://danluu.com/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;philosophize-this&quot;&gt;Philosophize this&lt;/h2&gt;
&lt;p&gt;I really enjoyed this &lt;a href=&quot;http://philosophizethis.org/&quot;&gt;podcast&lt;/a&gt;. He goes trough all great philosphors in chronoloigical order, which as a side effect helps you understand history better. It also made me think about my own life.&lt;/p&gt;
&lt;h2 id=&quot;xoreaxeaxeax&quot;&gt;xoreaxeaxeax&lt;/h2&gt;
&lt;p&gt;Everything in &lt;a href=&quot;https://github.com/xoreaxeaxeax/&quot;&gt;this github&lt;/a&gt; profile page is &lt;del&gt;insane&lt;/del&gt; beautifull. &lt;a href=&quot;https://www.youtube.com/watch?v=KrksBdWcZgQ&amp;amp;feature=youtu.be&amp;amp;t=1250&quot;&gt;This youtube&lt;/a&gt; explains the sandsifter thing in quite detail.&lt;/p&gt;
&lt;h1 id=&quot;reading&quot;&gt;Reading&lt;/h1&gt;
&lt;h2 id=&quot;books-in-public-domain&quot;&gt;Books in public domain&lt;/h2&gt;
&lt;p&gt;I’ve been reading the ‘classics’, of which many are in public domain. No need to spend precious money on something which ought to be free. Project gutenberg offers public domain ebooks for free:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gutenberg.org/&quot;&gt;https://www.gutenberg.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I do recommend donating to them though. &lt;a href=&quot;https://www.gutenberg.org/wiki/Gutenberg:Project_Gutenberg_Literary_Archive_Foundation&quot;&gt;They’re doing important work&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;programming-for-personal-growth&quot;&gt;Programming for personal growth&lt;/h2&gt;
&lt;p&gt;A really well written article about how simple satisfication (with programming in this case) may make you more confident and happy in life: &lt;a href=&quot;https://medium.com/the-polymath-project/programming-for-personal-growth-64052e407894&quot;&gt;https://medium.com/the-polymath-project/programming-for-personal-growth-64052e407894&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;writing-well-by-george-orwell&quot;&gt;Writing well by george orwell&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://www.orwell.ru/library/essays/politics/english/e_polit&quot;&gt;http://www.orwell.ru/library/essays/politics/english/e_polit&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Any one interested in writing demands a read of that. It describes why texts are interesting or not. It suggests for example that each sentence should anwser these questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What am I trying to say?&lt;/li&gt;
&lt;li&gt;What words will express it?&lt;/li&gt;
&lt;li&gt;What image or idiom will make it clearer?&lt;/li&gt;
&lt;li&gt;Is this image fresh enough to have an effect?&lt;/li&gt;
&lt;li&gt;Could I put it more shortly?&lt;/li&gt;
&lt;li&gt;Have I said anything that is avoidably ugly?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It also explains why we see this horrible accedemic style such as: “If a new spirit is to be infused into this old country, there is one thorny and contentious reform which must be tackled, and that is the humanization and galvanization…”&lt;/p&gt;
&lt;h2 id=&quot;paul-graham-essays&quot;&gt;Paul graham essays&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://www.paulgraham.com/articles.html&quot;&gt;These&lt;/a&gt; are both inspiring as interesting. I’ve found myself identifying with much he wrote about. Especially now I’ve decided to start my own startup, it’s really motivating, although I know he writes those mostly to just get more candidates to chose from. I like to believe he also does it to genuinly help people. Getting a job is bad for your brainz.&lt;/p&gt;
&lt;h1 id=&quot;tools&quot;&gt;Tools&lt;/h1&gt;
&lt;h2 id=&quot;vps-comparison-sites&quot;&gt;Vps comparison sites&lt;/h2&gt;
&lt;p&gt;For if you just need a cheap computing device somewhere on the internet. I wanted one that had high CPU but didn’t care about the rest, this one found it: &lt;a href=&quot;http://vps-list.cryto.net/index.php?action=list&quot;&gt;http://vps-list.cryto.net/index.php?action=list&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;haskell-blogposts&quot;&gt;Haskell blogposts&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://kodimensional.dev/posts/2019-03-25-comonadic-builders&quot;&gt;Comonads for builders&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;anime&quot;&gt;Anime&lt;/h1&gt;
&lt;p&gt;I watch way to much anime. Sometimes I encounter little gems, recorded here.&lt;/p&gt;
&lt;h2 id=&quot;puella-magi-madoka-magica&quot;&gt;Puella Magi Madoka Magica&lt;/h2&gt;
&lt;p&gt;A beautifull juxtposition of childishness and despair. I don’t want to say anything because I’ll spoil it but give it a try, it’s so worth it.&lt;/p&gt;
&lt;h2 id=&quot;code-geass&quot;&gt;Code geass&lt;/h2&gt;
&lt;p&gt;This was one of my first gateway anime drugs. It’s an excellent classic keeping you on the edge of the seat all the way. All characters have good motivations and are believeable.&lt;/p&gt;
&lt;h2 id=&quot;soul-eater&quot;&gt;Soul eater&lt;/h2&gt;
&lt;p&gt;I especially liked the first season, it drags on for a bit after that. But the theme around crazy-ness being the enemy is really appealing to me.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Making money with foss</title>
    <link href="https://jappieklooster.nl/making-money-with-foss.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2017-05-22:/making-money-with-foss.html</id>
    <published>2017-05-22T00:00:00Z</published>
    <updated>2020-05-11T10:33:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="technique"/>
    <summary type="html">&lt;p&gt;In this blog post I will discuss how to make money with open source software. Why do you care? Making money of this model is hard, yet you got to pay the bills. Even though the free software variant is &lt;a href=&quot;https://www.gnu.org/philosophy/free-sw.en.html&quot;&gt;consumer friendly&lt;/a&gt;. (note that these consumers maybe businesses too).&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;In this blog post I will discuss how to make money with open source software. Why do you care? Making money of this model is hard, yet you got to pay the bills. Even though the free software variant is &lt;a href=&quot;https://www.gnu.org/philosophy/free-sw.en.html&quot;&gt;consumer friendly&lt;/a&gt;. (note that these consumers maybe businesses too). This is a big problem. Lot’s of projects are maintained in people’s unpaid free time, next to their day jobs. So they don’t really get the love they deserve. Can we fix this?&lt;/p&gt;
&lt;p&gt;I would like to do this myself full time. Lest I became &lt;a href=&quot;https://www.reddit.com/r/financialindependence/&quot;&gt;financially independent&lt;/a&gt;, I couldn’t. So in here I will list the options I found trough researching the subject. As both an overview to myself and to the interested reader.&lt;/p&gt;
&lt;h1 id=&quot;google-results&quot;&gt;Google results&lt;/h1&gt;
&lt;p&gt;In my naive approach I searched for &lt;a href=&quot;https://www.google.nl/search?q=making+money+with+foss&amp;amp;ie=utf-8&amp;amp;oe=utf-8&amp;amp;client=firefox-b&amp;amp;gfe_rd=cr&amp;amp;ei=50YjWYn_CdHU8geKob64BQ&quot;&gt;“Making money with foss”&lt;/a&gt;. The first site that came up was &lt;a href=&quot;http://www.infoworld.com/article/2612393/open-source-software/greed-is-good--9-open-source-secrets-to-making-money.html&quot;&gt;info world&lt;/a&gt;. This site was full of warning flags, for example having a click bait title and using a pagnation. After skimming the article it wasn’t about making money of an open source project, but potential reasons for open sourcing (part of) your code. It was aimed at mid to high level management, non technical texts are of no interest to me, mainly because they usually have an agenda.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;http://www.fosslc.org/drupal/node/131&quot;&gt;second article&lt;/a&gt; linked to &lt;a href=&quot;http://carlodaffara.conecta.it/?p=90&amp;amp;cpage=1#comment-50&quot;&gt;another page&lt;/a&gt; with a better list, but I couldn’t find it. The third &lt;a href=&quot;http://www.cio.com/article/3178621/open-source-tools/how-to-make-money-from-open-source-software.html&quot;&gt;article&lt;/a&gt; was just a summery of a video and wasn’t very focused. Okay so my search terms were bad. Time to be more specific.&lt;/p&gt;
&lt;p&gt;I searched for &lt;a href=&quot;https://www.google.nl/search?q=making+money+with+foss&amp;amp;ie=utf-8&amp;amp;oe=utf-8&amp;amp;client=firefox-b&amp;amp;gfe_rd=cr&amp;amp;ei=50YjWYn_CdHU8geKob64BQ#q=foss+business+models&quot;&gt;“foss business models”&lt;/a&gt;, you know you did something right when scholarly articles start being presented. There was an entire &lt;a href=&quot;https://en.wikipedia.org/wiki/Business_models_for_open-source_software&quot;&gt;Wikipedia page&lt;/a&gt; on the subject. I guess more people are really interested in this. So does this blog post die in the cradle? I say no, I can still give my opinions on that page. Another thing is that discussing this page on my blog will force me to closely look at the possibilities. Besides the fact that there is a (quite big) wiki on it only shows how much people care about this subject.&lt;/p&gt;
&lt;h1 id=&quot;the-business-models&quot;&gt;The Business models&lt;/h1&gt;
&lt;p&gt;The core problem open source software faces is not having a monopoly on distribution that copyright provides. Therefore we can’t sell it directly: Anyone can start distributing the software without asking anything for it, without running a loss because distribution is (practically) free for &lt;a href=&quot;https://stratechery.com/2015/aggregation-theory/&quot;&gt;software on the internet&lt;/a&gt;. Giving up this monopoly is a necessary requirement for open source, called the &lt;a href=&quot;https://www.gnu.org/philosophy/free-sw.en.html&quot;&gt;second and thirth freedoms&lt;/a&gt;. This is also done with the BSD like licenses, so we can consider it a part of open source. Therefore we need to find a way of making money by working around this restriction.&lt;/p&gt;
&lt;h2 id=&quot;sell-stuff-besides-software&quot;&gt;Sell stuff besides software&lt;/h2&gt;
&lt;p&gt;One of the primary strategies is selling stuff besides the software. Red Hat does this trough &lt;a href=&quot;https://en.wikipedia.org/wiki/Red_Hat#Business_model&quot;&gt;providing support contracts&lt;/a&gt; for example. This can be extended by providing certificates of expertise (which Red Hat also does).&lt;/p&gt;
&lt;p&gt;I don’t like this approach as it gives the incentive to make bad software. If your software is hard to use, then only you can sell support. You should make your software easy to use.&lt;/p&gt;
&lt;p&gt;Another strategy is selling of merchandise, such as fan &lt;a href=&quot;https://store.wikimedia.org/collections/accessories&quot;&gt;T-shirts or coffee cups&lt;/a&gt;. Which the wikimedia foundation does. Selling merchandise is quite clever because its much more easy for someone to buy ‘something’, rather than just donating. Besides its free advertisement for your project, &lt;em&gt;and&lt;/em&gt; your users now have something to identify themselves with. So I think if you have an opensource project you should seriously consider doing this.&lt;/p&gt;
&lt;p&gt;Finally a programmer can rent himself out to a project to add features or do bug fixes. These include &lt;a href=&quot;https://www.Bountysource.com/&quot;&gt;Bountysource&lt;/a&gt; or &lt;a href=&quot;https://en.wikipedia.org/wiki/Kickstarter&quot;&gt;kickstarter&lt;/a&gt;, where Bountysource is usually fix an issue first and then get paid whereas kickstarter works on promises. In essence you’re offering up your own time to work on a project. In both cases there is of course the persistent issue that its &lt;a href=&quot;https://softwareengineering.stackexchange.com/questions/648/how-to-respond-when-you-are-asked-for-an-estimate&quot;&gt;hard to decide&lt;/a&gt; how much time this will take. With kickstarter however you can estimate it better because you’re probably starting your own bigger project, so the overhead of estimation is smaller. With Bountysource each bounty requires its own estimate and these are often smaller, think of about \$100, its hard to decide to even bother with that. Another issue with Bountysource is that you have to switch from project to project often, which requires a lot of getting familiar with the code base overhead. The model of Bountysource is less then perfect to live off. Although for existing developers of a project its a great motivation to work a little more. But don’t expect strangers to ‘join in’, just because of the bounties unless they’re highly valued. In fact you can see that few people ‘live’ off Bountysource just by the overview of bounty hunters. Only three people at the time of writing got over \$2000 in the last 90 days and only 9 over \$1000.&lt;/p&gt;
&lt;p&gt;In the strategy of renting yourself out is going to interested parties yourself and offer to write software. I’ve attempted this at times with for example &lt;a href=&quot;https://github.com/jappeace/offertex&quot;&gt;offertex&lt;/a&gt; and &lt;a href=&quot;https://github.com/jappeace/schijt-je-rijk&quot;&gt;schijt je rijk&lt;/a&gt;. The issue that always gets me is negotiating about price. And of course once the work is finished, you need to find &lt;em&gt;more&lt;/em&gt; work. Therefore you won’t get better overtime. Imitating red hat with support contracts could do that, but starting with that on your own is hard. Although I had other factors working against me, living in a remote village didn’t help. So you mileage may vary.&lt;/p&gt;
&lt;h2 id=&quot;donations&quot;&gt;Donations&lt;/h2&gt;
&lt;p&gt;Another powerful trick of trying to become self sustained on software is using donations. The big issue with this is of course getting people to donate in the first place. A famous example of a donation scheme as that of &lt;a href=&quot;http://www-archive.mozilla.org/press/mozilla-2004-12-15.html&quot;&gt;mozzilla firefox 1.0 release&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Recently another option has popped up in the form of &lt;a href=&quot;https://www.patreon.com/&quot;&gt;patreon&lt;/a&gt;. The idea is pretty simple, subscribe to a creator and every time he puts something out (or every month) donate a small amount decided by you. &lt;a href=&quot;https://www.patreon.com/landley&quot;&gt;Some&lt;/a&gt; &lt;a href=&quot;https://www.patreon.com/kozec&quot;&gt;developers&lt;/a&gt; &lt;a href=&quot;https://www.patreon.com/bcachefs&quot;&gt;have&lt;/a&gt; &lt;a href=&quot;https://www.patreon.com/pippin&quot;&gt;embraced&lt;/a&gt; &lt;a href=&quot;https://www.reddit.com/r/linux/comments/5omtvg/patreons_to_support_open_source_projects_please/&quot;&gt;this idea&lt;/a&gt;, although I haven’t seen anyone that earns self sustaining amounts. It does provide a reliable income stream and is aimed at &lt;em&gt;individuals&lt;/em&gt;, and since there are &lt;a href=&quot;https://www.patreon.com/cgpgrey&quot;&gt;other&lt;/a&gt; &lt;a href=&quot;https://www.patreon.com/avasdemon&quot;&gt;creators&lt;/a&gt; who have managed to get to a sustainable level. We can expect this to happen eventually for software developers too.&lt;/p&gt;
&lt;p&gt;The big advantage patreon offers over Bountysource is that, rather than having to think about how much time creating a feature costs as with Bountysource, you can just continue improving the project how you think it should be done. Of course some trust in the developer is necessary for that, Bountysource doesn’t have that problem, since payment is done afterwards and I assume regulated by Bountysource. However apparently Bountysource offers a similar service &lt;a href=&quot;https://salt.bountysource.com/teams/neovim&quot;&gt;for projects&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Another approach to this is to start a foundation. Blender is developed like &lt;a href=&quot;https://www.blender.org/foundation/&quot;&gt;this&lt;/a&gt;, and if your project has any kind of traction, do consider this. Trusting a foundation is much more easy because they’re regulated by law.&lt;/p&gt;
&lt;p&gt;A more recent iteration of donations is using twitch. Essentially you’re just explaining what you’re doing on a live stream and then people can ask questions while you’re programming. Twitch handles the payment processing for you.&lt;/p&gt;
&lt;h2 id=&quot;advertisements&quot;&gt;Advertisements&lt;/h2&gt;
&lt;p&gt;A trick often overlooked by most developers is advertising. In principle free software is not against the idea of advertising. However a problem with this is that anyone can take your software, remove the advertisements, and redistribute the add free version. You can prevent this from happening by offering two versions, one with adds and one without and then ask your users to support the project by downloading the one with adds.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Adblock_Plus#Controversy_over_ad_filtering_and_ad_whitelisting&quot;&gt;Addblock plus&lt;/a&gt; famously white listed adds as a way of generating revenue. It may be considered hypocritical, but remember that as free software anyone can fork it and remove this feature. Not that you have to since there are already &lt;a href=&quot;https://github.com/gorhill/uBlock&quot;&gt;alternatives&lt;/a&gt;. Note that although Adblock Plus probably made quite a good load of money with their white listing program, it will probably kill the project eventually. Because now they’re essentially running an extortion racket, becoming nothing more than parasites and providing lower quality user experience. I imagine the people who go out of their way to install an ad blocker are not the kind of people who are satisfied with an ever laxer white list.&lt;/p&gt;
&lt;h2 id=&quot;crypto-currency&quot;&gt;Crypto Currency&lt;/h2&gt;
&lt;p&gt;There is an opportunity in crypto too. Although this immediately sounds fishy. I’d say that taking a couple cycles per minute to do some mining isn’t &lt;em&gt;that&lt;/em&gt; bad. I mean how is it any different from stealing a users attention with advertisements? It’s probably even better because the users’ time is more valuable than machine cycles. No wonder that google &lt;a href=&quot;https://www.theregister.co.uk/2018/03/14/google_cracks_down_on_crypto_with_ad_ban_from_june/&quot;&gt;cracked down&lt;/a&gt; on this. Crypto is a substitute for advertising, Google is essentially a massive ad company. But this has the same problem as advertisment in that forks will occur which would take it out.&lt;/p&gt;
&lt;h2 id=&quot;license-tricks&quot;&gt;License tricks&lt;/h2&gt;
&lt;p&gt;The final category for making money with open source is license trickery. So this comes from the idea that, if you are the sole copyright holder, you can put the software under various licenses. Note that it is a big if to be the sole copyright holder, you need consent that any contributor is handing over their copyright. And as we will see in the re-license case, this can be abused. Which increases contributing barrier significantly. But in return as project owner you get a lot more possibilities for making money.&lt;/p&gt;
&lt;p&gt;Dual licenses are a practice where you offer one open license, and another business aimed license which promises more support than the open license or removes restrictions (such as forcing open source). This is &lt;a href=&quot;http://lucumr.pocoo.org/2013/7/23/licensing/#the-stricter-gpl&quot;&gt;where AGPLV3 shines&lt;/a&gt;, original authors can offer large organizations an alternative license, however downstream receivers of the code under AGPL cannot do this. &lt;a href=&quot;https://en.wikipedia.org/wiki/MongoDB&quot;&gt;Mongodb&lt;/a&gt; is an example that does this and they can only do this by asking contributors to &lt;a href=&quot;https://www.mongodb.com/legal/contributor-agreement&quot;&gt;hand over copyright&lt;/a&gt;. As a contributor you should be wary of doing this, copy left doesn’t work if you hand over copyright. If you work under BSD or MIT kind of licenses it doesn’t matter (and I assume you already came to terms with this).&lt;/p&gt;
&lt;p&gt;However, this does allow a company to thrive upon open source. A company is still required to hoard in the business deals with other companies, and to collect the copyright assignments from contributors. It may be taken over similarly as Oracle did to Sun. But the AGPL based code was already under license, so the community can step in and take over development, as happened with Illumos (Solaris fork) after Oracle went on its rampage. Although a recent &lt;a href=&quot;https://stratechery.com/2019/aws-mongodb-and-the-economic-realities-of-open-source/&quot;&gt;article&lt;/a&gt; by Ben Thompson cast some doubt on the long term efficacy of this strategy.&lt;/p&gt;
&lt;p&gt;This has however a darker side in potential license trolling. Which &lt;a href=&quot;https://lists.debian.org/debian-legal/2013/07/msg00000.html&quot;&gt;Oracle (who else) did&lt;/a&gt; for example with a database. Changing from BSD to AGPLv3, which in case of Debian required around 100 other dependent packages to change to AGPLv3 too. Which of course is not going to happen. Oracle probably did this to force users of that database to take a commercial license instead, taking foss projects (such as Debian) as collateral damage.&lt;/p&gt;
&lt;h2 id=&quot;proprietary-extensions&quot;&gt;Proprietary extensions&lt;/h2&gt;
&lt;p&gt;Proprietary extensions involve releasing an open source core and add (usually business centred) proprietary extensions. The Wikipedia page lists several example but the one I’m personally familiar with is the IntelliJ project. Which is &lt;a href=&quot;https://github.com/JetBrains/intellij-community&quot;&gt;opensource&lt;/a&gt;, has a &lt;a href=&quot;https://www.jetbrains.com/idea/features/editions_comparison_matrix.html&quot;&gt;proprietary paid extension&lt;/a&gt;, and also a &lt;a href=&quot;http://www.jetbrains.org/display/IJOS/Contributor+Agreement&quot;&gt;cla&lt;/a&gt; (which doesn’t hand over copyright but does a similar thing, licenses a right to copy).&lt;/p&gt;
&lt;p&gt;IntelliJ is kind off open source, but many developers want to pay for things such as CSS or JavaScript support. Although I’d say any text editor can do that, such as &lt;a href=&quot;http://spacemacs.org/&quot;&gt;spacemacs&lt;/a&gt;. where IntelliJ shines is Java and Scala. As far as I can see are the ‘supported’ features, just bells and whistles. However they maybe valuable for a professional developer, or to a software house to which the license fees are nothing compared to developer time.&lt;/p&gt;
&lt;p&gt;Because IntelliJ is open source it allowed Google to create android studio. This is great for the IntelliJ team because now there is another party that is dependent on their core of which they hold all copyright. Google may help developing the IntelliJ Java core, just to get it to work for android developers. This is the thing most companies are after with open source, free programming manpower.&lt;/p&gt;
&lt;h2 id=&quot;delayed-open-sourcing&quot;&gt;Delayed open sourcing&lt;/h2&gt;
&lt;p&gt;This is the thing &lt;a href=&quot;https://en.wikipedia.org/wiki/John_Carmack&quot;&gt;John Carmack&lt;/a&gt; famously did with ID tech. After some time selling the games he would release the source of the games. Which he did for &lt;a href=&quot;https://github.com/id-Software/DOOM&quot;&gt;Doom&lt;/a&gt;, &lt;a href=&quot;https://github.com/id-Software/Quake&quot;&gt;Quacke&lt;/a&gt; even &lt;a href=&quot;https://github.com/id-Software/DOOM-3&quot;&gt;Doom 3&lt;/a&gt;. This in turn led the games to be developed upon for a long time after their release. For example &lt;a href=&quot;https://ioquake3.org/&quot;&gt;ioquake3&lt;/a&gt;, still actively develops the quake engine, driving sales of the quake game itself because the assets aren’t freely available.&lt;/p&gt;
&lt;p&gt;So he open sourced partly dated tech, because he was confident he could do better now. And he increased sales of already released games, because people wanted to hack on it. I think this is pretty genius, gaining some extra juice out of old projects. The really nice thing is that the lifespan of these games has tremendously increased. Creating a core of die-hard followers. Doom has been ported to essentially &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_Doom_source_ports&quot;&gt;everything&lt;/a&gt;. It’s a mystery to me why not more companies are doing this.&lt;/p&gt;
&lt;h2 id=&quot;re-license&quot;&gt;Re-license&lt;/h2&gt;
&lt;p&gt;If you are the sole copyright holder, you can stop distributing under the open source license and re-license it. Originally I didn’t want to include this option because you’re no longer doing foss at this point. But if your project is dying, because you can’t give it enough love. This maybe totally valid. It’s your project after all, if you can make a valid business out of it by stop doing opensource I’d give you nothing but praise.&lt;/p&gt;
&lt;p&gt;Having said that, this also opens up the opportunity to hate upon Oracle. So lets hate upon Oracle.&lt;/p&gt;
&lt;p&gt;So if we Google: &lt;a href=&quot;https://www.google.nl/search?q=why+oracle+is+horrible&amp;amp;ie=utf-8&amp;amp;oe=utf-8&amp;amp;client=firefox-b&amp;amp;gfe_rd=cr&amp;amp;ei=Hi0sWcTQNOvGXqT5o7gM&quot;&gt;Why oracle is horrible&lt;/a&gt;, we can get some &lt;a href=&quot;https://www.quora.com/Whats-so-bad-about-Oracle&quot;&gt;dumb&lt;/a&gt; &lt;a href=&quot;https://www.quora.com/Why-do-some-people-hate-Oracle&quot;&gt;quora&lt;/a&gt; answers. These are just not the point. This &lt;a href=&quot;https://www.reddit.com/r/linux/comments/2e2c1o/what_do_we_hate_oracle_for/&quot;&gt;reddit thread&lt;/a&gt;, sums it up nicely. What is really dog kicking evil were the Solaris issues, which is discussed in this &lt;a href=&quot;https://www.youtube.com/watch?v=-zRN7XLCRhc#t=33m0s&quot;&gt;this video&lt;/a&gt;. A little further in &lt;a href=&quot;https://www.youtube.com/watch?v=-zRN7XLCRhc&amp;amp;feature=youtu.be&amp;amp;t=2482&quot;&gt;the video&lt;/a&gt; its is explained how it happened. So what happened is that Oracle obtained all copyright from various authors by buying SUN which required initially handing over copyright, Open Solaris was closed by Oracle with a re-license. This was only possible because Sun asked contributors to fork over copyright. What we can learn from this is that if you contribute to free software and care about it, &lt;strong&gt;never hand over copyright&lt;/strong&gt;. I’m happy to say however that a fork of Solaris occurred called &lt;a href=&quot;https://wiki.illumos.org/display/illumos/illumos+Home&quot;&gt;Illumos&lt;/a&gt; that seems to still be active.&lt;/p&gt;
&lt;h1 id=&quot;in-conclusion&quot;&gt;In conclusion&lt;/h1&gt;
&lt;p&gt;Because we are interested in making money, this post will took us all over the place. On the one hand we have the greedy businesses, and on the other side the diligent developer. Licenses were never discussed in university, which is interesting because this is &lt;em&gt;the&lt;/em&gt; method for making money with software. I think having discussed the overview and shown some concrete examples was a good exercise. I was not aware at all for example of the AGPLv3 practices which are interesting (without passing moral judgment).&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Tool survey</title>
    <link href="https://jappieklooster.nl/tool-survey.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2017-04-01:/tool-survey.html</id>
    <published>2017-04-01T00:00:00Z</published>
    <updated>2017-04-01T00:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;Some time ago I made a blog post about thesis &lt;a href=&quot;thesis-writing-tips.html&quot;&gt;writing tips&lt;/a&gt;. However while writing that a large part started to be about text editing tools and version control. To keep the thesis writing tips post more focused I postponed writing about that. This post treats my tools of&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Some time ago I made a blog post about thesis &lt;a href=&quot;thesis-writing-tips.html&quot;&gt;writing tips&lt;/a&gt;. However while writing that a large part started to be about text editing tools and version control. To keep the thesis writing tips post more focused I postponed writing about that. This post treats my tools of choice.&lt;/p&gt;
&lt;p&gt;All people will only ever care about a niche of tools. The reason is that in our world, we have too many choice to form an opinion about each of them. Tell me for example about your favorite pick axe or transport ship, you probably don’t have an opinion about these tools. Which just shows how more complex our society became compared to for example the stone age, where everyone had a favorite type of stone.&lt;/p&gt;
&lt;p&gt;Note that isn’t enough to form an opinion about a tool to care about it, you actually have to have used it for a while, and then switch to another quite different tool to start caring. Only once you switch you will form a deeper ‘bond’ with the new one or old one. I think I switch quite often. Which brings us to another reason for this post, I want to compare my current tools of choice with those of future me.&lt;/p&gt;
&lt;h1 id=&quot;operating-system&quot;&gt;Operating System&lt;/h1&gt;
&lt;p&gt;This is where things will get interesting. The main theme of my selection has always been tweakability. I want to be able to change things I don’t like. This is seen most clearly from my OS choice: &lt;a href=&quot;https://gentoo.org/&quot;&gt;Gentoo/Linux&lt;/a&gt;, this is a source based rolling release distribution. Most distributions work with pre-compiled software. However software provides often at compile time, flags that enable or disable features. Gentoo standardizes this and allows you to specify per software package which options you want or don’t want.&lt;/p&gt;
&lt;p&gt;The reason I chose Gentoo initially is more petty, a class mate of my was using it, and I didn’t even understand what “source based” or “rolling release” meant. I wanted to be at least at the same level as my classmates, so in my stubbornness I spent about 2 weeks installing it on my own the first time, with help of the handbook. It took so long because I didn’t know anything really about the shell and unix, Gentoo really forces you to learn.&lt;/p&gt;
&lt;p&gt;Now I stick with Gentoo because it allows me to do customizations, while updates won’t break these. Gentoo’s packagemanager is very careful in preserving configuration files. Unlike Ubuntu, which upgraded me out of my custom alternatively installed desktop environment. Gentoo has to be more careful, because of its inherent configurable-ness. Whereas Ubuntu provides ease of use, which goes hand in hand with, knowing it better than the user.&lt;/p&gt;
&lt;h1 id=&quot;control-everything-with-keyboard&quot;&gt;Control everything with keyboard&lt;/h1&gt;
&lt;p&gt;During my software engineering classes I got introduced to the idea that the mouse is pretty slow to work with. The key difference between mouse usage and keyboard only usage is that mouse usage often involves searching the right place to click, wheareas using the keyboard is just doing what you want to do. By systematically making the mouse less important, working with the computer becomes more like playing an instrument. I use several programs that minimize mouse usage:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://i3wm.org/&quot;&gt;i3-wm&lt;/a&gt; or its wayland successor &lt;a href=&quot;http://swaywm.org/&quot;&gt;sway&lt;/a&gt; (as soon as wayland takes off, it’ll probably be some years later) This is the window manager that fills the screen with active window by default, or splits it if there are multiple windows open. It also has work spaces (basically groups of windows under a global tabbing system).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.vim.org/&quot;&gt;vim&lt;/a&gt;. This is a text editor with “modes”. normal mode is navigation, and insert mode is for typing text. If you work a lot with text its definitely worth learning this. But beware, expect the first two weeks or so of using this program to have lower productivity. (and basically no productivity the first day ;) )&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://spacemacs.org/&quot;&gt;Spacemacs&lt;/a&gt;. This is an evil combination of Emacs and vim. I use this for software development and writing larger texts. whereas I use vim for quick and dirty edits (besides vim is available on every Unix system whereas Emacs and especially Spacemacs is not). Oh I also run this in daemon mode so that I can use i3 to move windows rather than the pretty bad buffer navigation of Emacs.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ranger/ranger&quot;&gt;Ranger&lt;/a&gt;. This is a file browser that works with vim like bindings, I also have a Spacemacs plugin that does the same inside Spacemacs. Actually if you combine i3 + vim + ranger you have a really solid IDE.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I haven’t found a good way to eliminate mouse usage from the browsing experience. There are plugins that give vim like navigation, but I never really found them compelling to use. This maybe just personal taste, but I think it also has to do that browsing, is usually quite similar to searching.&lt;/p&gt;
&lt;h1 id=&quot;write-everything-down&quot;&gt;Write everything down&lt;/h1&gt;
&lt;p&gt;I’ve slowly over the years come to realize how unreliable my memory is and how liberating it is to write stuff down. No need to think about something which you’ve already written down. I have a little idea project in which I write down random ideas I have for programs or systems, even political once. The reason for doing this is that the idea can then exit my mind without the fear of forgetting it, often I will later extend it or realize its unfeasible or impractical.&lt;/p&gt;
&lt;p&gt;To this project I also added a planning file which contains some stuff I probably should work on. This really helps focusing and narrowing down a direction I want to go in. They also provide a dialogue between passed me, current me, and eventually future me. It was a classmate who brought me up on this idea, but CGPGrey pointed out the dialogue aspect. The dialogue aspect also holds true for ideas, but ideas are generally not plans yet. Plans have some form of commitment too it, you just need to find the time.&lt;/p&gt;
&lt;h2 id=&quot;version-control&quot;&gt;Version control&lt;/h2&gt;
&lt;p&gt;I mentioned “projects” before, by this I mean I have the files under version control. I use &lt;a href=&quot;https://git-scm.com/&quot;&gt;git&lt;/a&gt; for version control.&lt;/p&gt;
&lt;p&gt;Wait, I’ll clarify the concept of version control first. Think of it as Ctrl+Z on steroids managed by a dedicated program. It can track changes over multiple files and directories, and with each change you want to save you can add a message. It can also send these changes to other machines or ‘locations’. There are actually a bunch of options for this &lt;a href=&quot;https://subversion.apache.org/&quot;&gt;svn&lt;/a&gt;, &lt;a href=&quot;http://www.nongnu.org/cvs/&quot;&gt;cvs&lt;/a&gt;, &lt;a href=&quot;http://bazaar.canonical.com/en/&quot;&gt;bazaar&lt;/a&gt; and many more. At this point its safe to say however that git crushed all competition, the reason for this is that the architecture of git compared to other systems is dead simple. Also &lt;a href=&quot;https://github.com/&quot;&gt;github&lt;/a&gt; helped a lot.&lt;/p&gt;
&lt;p&gt;However I don’t just use git for just programming projects, no. I use also it for important configuration files, my todo list, my idea project and of course my thesis. Basically most information I put into the computer that can be represented as plain text without to much trouble, I put in git. The reason for this is that it has a much nicer history than for example dropbox, and provides advanced merge mechanisms. Besides with git I don’t need to have to trust some external service, since its decentralized.&lt;/p&gt;
&lt;p&gt;Actually git has slowly become a sort of diary of mine. For example when I delete items from the planning or ideas they’re not truly gone, just stored in a previous commit (=ctrl+z log entry), with a message why the change happened. I think future me, or historians if I ever become that important, can track most of my life at this point with help of git. In the back of my mind I’ve actually developed an opinion that git usage is a basic computer skill and should be thought on schools, since it could make collaborative work on documents much easier. Although I know this won’t happen in the near future, since it would also require the rejection of binary formats for text processing all together. Which is something harder to ask than replacing with an open format, with which entire &lt;a href=&quot;https://www.documentfoundation.org/&quot;&gt;foundations&lt;/a&gt; have trouble pushing upon people and organizations.&lt;/p&gt;
&lt;h1 id=&quot;discovery&quot;&gt;Discovery&lt;/h1&gt;
&lt;p&gt;The source of finding new tools is an important thing to discuss. I think I had three major sources over the years:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;School, mandatory content&lt;/li&gt;
&lt;li&gt;School, classmates&lt;/li&gt;
&lt;li&gt;Reddit&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first two sources have essentially become closed since I started writing the thesis and no longer physically are at the school. However I’m expecting a fourth source in the form of colleagues once I start working.&lt;/p&gt;
&lt;p&gt;I think mandatory school content is generally the worst quality. First of all it lags behind the inovation curve. Secondly most people already know how to use that since its mandatory so you’ll have most competition on that area if you’re an expert. Finally it doesn’t really give you much of opinions on the matter at all. Giving dumb reasons for learning the tool “you have to”, or “this is industry standard” rather than giving a comparison between alternatives. However I did find that the school of applied science (Windesheim), usually was even further behind than the University of Utrecht. But maybe it was because I was following a master course rather than a bachelor. Note that I’m not really talking about the theory, but the &lt;em&gt;tools&lt;/em&gt; with which you can put theory into practice.&lt;/p&gt;
&lt;p&gt;Classmates are a much better source, in fact one of the best I think because they can tell you their opinion, and opinions are &lt;em&gt;so&lt;/em&gt; important. Even if you disagree with them, it forces you to defend your position and reconsider, which makes your choice stronger. Or if you fail you may flip and gain a new experience and form new opinions.&lt;/p&gt;
&lt;p&gt;I have mixed feelings about reddit, its a major source of distraction, but it has a lot of gems (not even hidden, I mean reddit has search functionality!). I often subscribe to sub-reddits of tools I’m interested in using to learn more about them and to lurk on those valuable opinions. But the hivemind, seriously fuck that politically correct piece of shit… &lt;sup&gt;&lt;sup&gt;I love you&lt;/sup&gt;&lt;/sup&gt;. Our relation is complicated.&lt;/p&gt;
&lt;h1 id=&quot;paranoia-security&quot;&gt;Paranoia (security)&lt;/h1&gt;
&lt;p&gt;I encountered the abysmal state of computer security first in Windesheim. I won’t talk about the state of computer security because I don’t care. What they did on Windesheim, was: They just taught is to hack so that we would know how to defend. I hated it. You may say, oh isn’t hacking super exciting? No its not. Its not really constructive, you just need to think in terms of possibilities and try out everything. Rather than programming, where you just try out something that comes to mind and then later review to see how to improve (or stop once satisfied). Then this gets mixed with the idea that paranoia is &lt;em&gt;good&lt;/em&gt;. I know from my experience that under certain circumstances I have paranoid tendencies, I don’t need to promote that in my life. Finally its never enough. Being secure is always a moving target unless you can formally proof you’re secured, which you can’t because that’s as &lt;a href=&quot;https://stackoverflow.com/questions/476959/why-cant-programs-be-proven&quot;&gt;hard as programming&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since that class, which is now almost 3 to 4 years ago, I had several concerns in the back of my mind. My weak set of just 3 passwords used rationally. If one got cracked I would lose a third of my online accounts. If my email account got cracked I would lose everything. And the fact my identity could easily be faked. So I addressed these concerns recently (about 3 months ago).&lt;/p&gt;
&lt;p&gt;To start with the most important issue, passwords. For this I use something called a ‘password manager’ which called &lt;a href=&quot;http://keepass.info/&quot;&gt;Keepass&lt;/a&gt;, actually I use the &lt;a href=&quot;https://keepassxc.org&quot;&gt;qt based one&lt;/a&gt; (works better with Linux). I use this one because its opensource, and has a GUI and an android client. The reason for using this is complicated and explained very well &lt;a href=&quot;https://www.youtube.com/watch?v=3NjQ9b3pgIg&quot;&gt;here&lt;/a&gt; but basically its more safe than memorizing several and it also happens to be more convenient. I use &lt;a href=&quot;https://syncthing.net/&quot;&gt;syncthing&lt;/a&gt; to share the database with my phone and my server, I don’t wanna lose that. I just have a huge password, I didn’t want to do the keyfile, because I’m afraid to lose that.&lt;/p&gt;
&lt;p&gt;I recommend everyone to use a password manager. Its easier to use, it can autofill passwords in &lt;a href=&quot;https://github.com/pfn/keepasshttp&quot;&gt;your browser&lt;/a&gt; and you just have to remember the master password. It allows you to have much less “stuff” in your mind and its more secure. I even put WIFI passwords in there. &lt;a href=&quot;https://wiki.gnome.org/Projects/NetworkManager&quot;&gt;Network manager&lt;/a&gt; also allows viewing of WIFI passwords, at least in &lt;a href=&quot;https://www.kde.org/plasma-desktop&quot;&gt;plasma&lt;/a&gt;, but since I’m almost always in i3 its just easier to have in Keepass. Besides now I have the WIFI passwords on my phone too.&lt;/p&gt;
&lt;p&gt;For authentication (making it difficult to steal my identity), I went trough the effort of setting up &lt;a href=&quot;https://www.gnupg.org/&quot;&gt;pgp&lt;/a&gt; for email and git. For email I use the &lt;a href=&quot;https://www.mozilla.org/en-US/thunderbird/&quot;&gt;Thunderbird&lt;/a&gt; extension &lt;a href=&quot;https://www.enigmail.net/index.php/en/&quot;&gt;enigmail&lt;/a&gt;. All my git commits and emails are signed now. To configure signing in git I followed &lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work&quot;&gt;this&lt;/a&gt;. &lt;a href=&quot;https://stackoverflow.com/questions/10161198/is-there-a-way-to-autosign-commits-in-git-with-a-gpg-key&quot;&gt;This&lt;/a&gt; stackoverflow question explains how to sign automatically.&lt;/p&gt;
&lt;p&gt;Linus Torvalds &lt;a href=&quot;http://git.661346.n2.nabble.com/GPG-signing-for-git-commit-td2582986.html&quot;&gt;believes&lt;/a&gt; auto signing is unnecessary. I disagree, it makes it much harder to steal my identity, without me needing to think about it.&lt;/p&gt;
&lt;p&gt;For email I know its a good thing to sign, spoofing email is &lt;a href=&quot;https://lifehacker.com/how-spammers-spoof-your-email-address-and-how-to-prote-1579478914&quot;&gt;incredibly easy&lt;/a&gt; and by signing it, spoofing my email becomes difficult. Assuming the recipient checks it, which most people don’t, but if nobody sets this up nobody will ever start using it. So I setup email signing more as a matter of principle I guess. Oh and btw, if everyone actually did this, the life of spammers would become significantly harder, since spoofing is no longer an option. So shame on you if you don’t do this.&lt;/p&gt;
&lt;p&gt;I also setup a VPN on the server with &lt;a href=&quot;https://openvpn.net/&quot;&gt;openvpn&lt;/a&gt;, mainly in case I want to go to china again, I’ll just have that around. It allows you to visit google there. The VPN client is basically a use flag for network manager.&lt;/p&gt;
&lt;p&gt;Using a VPN by default won’t help you with security much. Maybe if you use not encrypted WIFI, but even then if you visit https websites the connection is encrypted anyway. Using a service for it is especially dumb, because now that service provider has always access to your packets. If you want to do a VPN you need to setup your own &lt;a href=&quot;http://www.comparevps.com/&quot;&gt;VPS&lt;/a&gt;, and then setup your own &lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-set-up-an-openvpn-server-on-ubuntu-16-04&quot;&gt;VPS&lt;/a&gt;. I actually host this website and the VPN on the same VPS at &lt;a href=&quot;https://galaxyhostplus.com&quot;&gt;Galaxy host plus&lt;/a&gt;. with the cheapest offering &lt;code&gt;VPS OpenVZ Hosting - OVZ - 2016 - LC1&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&quot;other-random-stuff&quot;&gt;Other random stuff&lt;/h1&gt;
&lt;p&gt;I don’t know what to say about most of these.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cgag/hostblock&quot;&gt;Hostblock&lt;/a&gt; for disabling reddit, youtube and facebook while working on stuff. This is a huge productivity boost&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mozilla.org/en-US/firefox/new/?scene=2&quot;&gt;Firefox&lt;/a&gt; for browsing. I think google has enough opurtinity to spy upon me. They won’t get my browser.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://help.gnome.org/users/gnome-terminal/stable/&quot;&gt;gnome terminal&lt;/a&gt; as terminal emulator, wait I have a reason for this. It’ll rewrap text on screenresizing. &lt;a href=&quot;https://konsole.kde.org/&quot;&gt;Konsole&lt;/a&gt; won’t do that, but konsole renders &lt;a href=&quot;https://github.com/tonsky/FiraCode&quot;&gt;firacode&lt;/a&gt; litagures correctly.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Valloric/YouCompleteMe&quot;&gt;You complete me&lt;/a&gt; to give both Spacemacs and vim better contextual awareness for various languages&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://orgmode.org/&quot;&gt;org mode&lt;/a&gt; to write any document in.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fbreader.org/&quot;&gt;Fbreader&lt;/a&gt; for reading ebooks.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://qpdf.sourceforge.net/&quot;&gt;qpdf&lt;/a&gt; for pdf files.&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Comparing tax in different countries</title>
    <link href="https://jappieklooster.nl/comparing-tax-in-different-countries.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2017-03-02:/comparing-tax-in-different-countries.html</id>
    <published>2017-03-02T00:00:00Z</published>
    <updated>2017-03-02T00:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;p&gt;Soon I will be graduating from my masters in AI. However since I was planning to go abroad I wanted to see how much worse or better taxation laws are compared to my own country (The Netherlands).&lt;/p&gt;
&lt;p&gt;For starters we will compare with the eastern neighbours (Germany). Scale 3 has&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Soon I will be graduating from my masters in AI. However since I was planning to go abroad I wanted to see how much worse or better taxation laws are compared to my own country (The Netherlands).&lt;/p&gt;
&lt;p&gt;For starters we will compare with the eastern neighbours (Germany). Scale 3 has been removed because its not relevant for me:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;NL&lt;/th&gt;
&lt;th&gt;from&lt;/th&gt;
&lt;th&gt;till&lt;/th&gt;
&lt;th&gt;%&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;€ 0&lt;/td&gt;
&lt;td&gt;€ 19’982&lt;/td&gt;
&lt;td&gt;36,55%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;€ 19’982&lt;/td&gt;
&lt;td&gt;€ 67’072&lt;/td&gt;
&lt;td&gt;40,80%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;€ 67’072&lt;/td&gt;
&lt;td&gt;€ ∞&lt;/td&gt;
&lt;td&gt;52,00%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;a href=&quot;http://belastingschijven.net/belastingschijven-2017/&quot;&gt;source&lt;/a&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;DE&lt;/th&gt;
&lt;th&gt;from&lt;/th&gt;
&lt;th&gt;till&lt;/th&gt;
&lt;th&gt;%&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;€ 0&lt;/td&gt;
&lt;td&gt;€ 7’664&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;€ 7’665&lt;/td&gt;
&lt;td&gt;€ 52’153&lt;/td&gt;
&lt;td&gt;15%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;€ 52’154&lt;/td&gt;
&lt;td&gt;€ 250’000&lt;/td&gt;
&lt;td&gt;42%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;€ 250’001&lt;/td&gt;
&lt;td&gt;€ ∞&lt;/td&gt;
&lt;td&gt;45%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;a href=&quot;http://www.cfe-eutax.org/taxation/personal-income-tax/germany&quot;&gt;source&lt;/a&gt;. Just glancing at it and you see a rather big difference. However its even worse with Australia:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;AU&lt;/th&gt;
&lt;th&gt;from&lt;/th&gt;
&lt;th&gt;till&lt;/th&gt;
&lt;th&gt;%&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;€ 0&lt;/td&gt;
&lt;td&gt;€ 13’250&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;€ 13’250&lt;/td&gt;
&lt;td&gt;€ 26’934&lt;/td&gt;
&lt;td&gt;9.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;€ 26’934&lt;/td&gt;
&lt;td&gt;€ 63’347&lt;/td&gt;
&lt;td&gt;22.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;€ 63’347&lt;/td&gt;
&lt;td&gt;€ 130’995&lt;/td&gt;
&lt;td&gt;30.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;€ 130’995&lt;/td&gt;
&lt;td&gt;€ ∞&lt;/td&gt;
&lt;td&gt;45%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Income_tax_in_Australia&quot;&gt;source&lt;/a&gt; (Converted to euros)&lt;/p&gt;
&lt;p&gt;So ok, say I earn 3500 euro’s per month, which is an entirely reasonable assumption since I saw multiple government &lt;a href=&quot;https://www.werkenvoornederland.nl/vacatures?vakgebied=CVG.08&amp;amp;werkdenkniveau=CWD.04&quot;&gt;vaccancies&lt;/a&gt; with my skill set (or lower) for around that price and I asked a recruiter too who said around that (actually he low-balled me with 3’000-3’500, but I guess that’s his job).&lt;/p&gt;
&lt;p&gt;So the amount per year is: &lt;span class=&quot;math display&quot;&gt;3500 × 12 = 42&lt;sup&gt;′&lt;/sup&gt;000&lt;/span&gt;,&lt;/p&gt;
&lt;p&gt;The tax I would pay in the Netherlands then would be: &lt;span class=&quot;math display&quot;&gt;19&lt;sup&gt;′&lt;/sup&gt;982 × 0.3655 + (42&lt;sup&gt;′&lt;/sup&gt;000 − 19&lt;sup&gt;′&lt;/sup&gt;982) × 0.408 = 16&lt;sup&gt;′&lt;/sup&gt;286&lt;/span&gt; or &lt;span class=&quot;math display&quot;&gt;16&lt;sup&gt;′&lt;/sup&gt;286/42&lt;sup&gt;′&lt;/sup&gt;000 = 39%&lt;/span&gt; goes to taxes from my total income.&lt;/p&gt;
&lt;p&gt;For Germany however &lt;span class=&quot;math display&quot;&gt;(42&lt;sup&gt;′&lt;/sup&gt;000 − 7&lt;sup&gt;′&lt;/sup&gt;664) × 0.15 = 5&lt;sup&gt;′&lt;/sup&gt;150&lt;/span&gt; or &lt;span class=&quot;math display&quot;&gt;5&lt;sup&gt;′&lt;/sup&gt;150/42&lt;sup&gt;′&lt;/sup&gt;000 = 12%&lt;/span&gt;. That’s quite a dramatic difference. On top of that the VAT is 2% lower in Germany so you’ll have 2% more purchasing power.&lt;/p&gt;
&lt;p&gt;So now to calculate for Australia.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;math display&quot;&gt;(26&lt;sup&gt;′&lt;/sup&gt;934 − 13&lt;sup&gt;′&lt;/sup&gt;250) × 0.097 + (42&lt;sup&gt;′&lt;/sup&gt;000 − 26&lt;sup&gt;′&lt;/sup&gt;934) × 0.228 = 4&lt;sup&gt;′&lt;/sup&gt;762&lt;/span&gt; or &lt;span class=&quot;math display&quot;&gt;4&lt;sup&gt;′&lt;/sup&gt;762/42&lt;sup&gt;′&lt;/sup&gt;000 = 11%&lt;/span&gt; in taxes, Australia also has a lower VAT (just 10%). And the amount of money going to ‘pensions’ is a lot lower in Australia, rather than 25% (hard to find a right source on this) of the Netherlands only 9% goes to it, which is by the way redeemable as soon as you leave (&lt;a href=&quot;https://auvisa.org/nl/working-holiday-visum-voor-australie/&quot;&gt;source&lt;/a&gt;). Which is perfect, I just go visit family for a week and get a fat paycheck, because I didn’t want to do pensions anyway in my twenties, I have other costs to worry about.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Optimus time!</title>
    <link href="https://jappieklooster.nl/optimus-time.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2017-01-29:/optimus-time.html</id>
    <published>2017-01-29T00:00:00Z</published>
    <updated>2017-01-29T00:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="tools"/>
    <summary type="html">&lt;p&gt;Using gentoo is a bliss most of the time. The package manager portage is one of the most advanced managers that I’ve ever used. Last week I encountered how much better it is than for example apt, when my old laptops power supply burned out and I had to resort&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Using gentoo is a bliss most of the time. The package manager portage is one of the most advanced managers that I’ve ever used. Last week I encountered how much better it is than for example apt, when my old laptops power supply burned out and I had to resort to a xubuntu machine. Apt has no capability for example to run multiple install processes at the same time, whereas portage just goes with that. Apt also has no propper versioning system, which makes python 2 and python 3 seperate packages, but portage can use slots for that. This has the advantage that the search tool results become a lot less cluttered.&lt;/p&gt;
&lt;p&gt;However using gentoo has also its disadvantages. It can demand a lot of time once you start tweaking with it. Yesterday I spent about 2 hours figuring out why my graphics card was slow. 3 hours trying to use the card in a dedicated manner ( rather than hot switching which the optimus technology does, promises to do, but doesn’t do). Which failed because documentation is often to technical and its hard to debug, because they sort of expect you know how to debug. I ended up with the galium driver which upon kvm from vmware?? That didn’t sound right, and indeed this was the software render.&lt;/p&gt;
&lt;p&gt;Then I tried using the bumlbebee and primus driver from the main portage tree and non masked primus variant instead of the bumblebee overlays ones. This maked primus run work again. (it was borke for about one year, and I used optirun -b primus instead which worked). using the mainline gentoo tree also revealed that apperanlty primus requires nvidia to have a use flag enabled. Its the thing I don’t like about useflags, how poorly they are documentated I think the idea is that normally portage will tell you what use flags you need, but not for edge cases (such as using an overlay).&lt;/p&gt;
&lt;p&gt;So at this time I was being hope full again because I got some results, therefore I did one last ditch attempt to try and use a dedicated one. I rebooted and X11 ended up in a black screen with a nonworking keyboard. Thanks X for taking con troll over everything (wayland still worked).&lt;/p&gt;
&lt;p&gt;If your keyboard fails you’re in big trouble, X is sort of optional to fix things, but without a keyboard you can’t even access the backup tty’s linux comes with (alt+{f1,f2,…}).&lt;/p&gt;
&lt;p&gt;So now I had to make a new live usb, because this new laptop has no cd player, and I only had live CD’s. With the live [usb|cd] the plan is to fix your system so you can boot at least into a tty. So in my situation it just involved disabling the display manager (which disables the keyboard). In case of systemd you just remove the symlink `/etc/systemd/system/display-manager.service`. So after I did taht I spend over 4 hours figuring out what was wrong with the display manager. Apparently this new bumbleed clashes with X11, I used the `/var/log/emerge.log` to figure this out (I kindoff forgot all the stuff I changed and for some reason journalctl recorded nothing of sddm. Also deleting the xorg.conf was a bad idea. it’ll also produce a black screen. However at this point I had about 5 different configuration of xorg so I just coppied the working one in there. I also found out that if you specify the wrong name in auto login of sddm you will also get a black screen but with active keyboard so you can just login to another tty to do more debugging.&lt;/p&gt;
&lt;p&gt;So this time the great optimus technlogy (which I really start to hate), has taking 9 hours. This is on top of the first time when I learned about bumblebee in my early gentoo/steam experience (I guess another 8 hours at least). And that one time optimus suddenly broke (perhaps 4 hours untill I found the optirun -b PRIME trick, prime is required btw otherwise steam won’t accept it).&lt;/p&gt;
&lt;p&gt;I don’t know, I’m salty at both optimus and gentoo to a lesser extend. I mean all these problems were just configuration problems I would’ve encountered too on other distro’s I guess. But gentoo makes it so easy to go out of your way and play with the configurations.&lt;/p&gt;
&lt;p&gt;Perhaps next time I should just go with an AMD laptop, I hear they are making tons of progress with their opensource drivers.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Thesis writing tips</title>
    <link href="https://jappieklooster.nl/thesis-writing-tips.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2017-01-14:/thesis-writing-tips.html</id>
    <published>2017-01-14T00:00:00Z</published>
    <updated>2017-01-14T00:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="technique"/>
    <summary type="html">&lt;p&gt;So I recently started writing my master thesis and looking at some of my fellow master students their work I realized that perhaps many people have trouble with managing references, quality control and keeping motivated.&lt;/p&gt;
&lt;p&gt;In this post I’ll explain how I managed to do it, most of these ideas&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;So I recently started writing my master thesis and looking at some of my fellow master students their work I realized that perhaps many people have trouble with managing references, quality control and keeping motivated.&lt;/p&gt;
&lt;p&gt;In this post I’ll explain how I managed to do it, most of these ideas are either directly stolen from my classmates, ripped from reddit and a few are my own “invention”, but others may already have thought of it.&lt;/p&gt;
&lt;p&gt;So perhaps the best way to see this post is as a aggragetion of techniques and &lt;del&gt;tools&lt;/del&gt; (the tools part will be moved to another post) I used to waste less time. So my advice to you is to skim this article and look for any ideas that seem interesting and try them out.&lt;/p&gt;
&lt;h1 id=&quot;reference-management&quot;&gt;Reference management&lt;/h1&gt;
&lt;p&gt;Reference management seems to be a thing which can be quite tricky. It is extremely tedious and dull work, and therefore I obviously don’t do it by hand. I use bibtex as core platform, I haven’t compared the available options but since it integrated with org-mode I was happy with it.&lt;/p&gt;
&lt;p&gt;To find papers I mainly use Google scholar trough the university proxy. However sometimes papers aren’t available for my university, so I’m forced to use &lt;a href=&quot;http://sci-hub.io/&quot;&gt;http://sci-hub.io/&lt;/a&gt; (if that link gets blocked in the future, try the &lt;a href=&quot;https://en.wikipedia.org/wiki/Sci-Hub&quot;&gt;wikipedia entry&lt;/a&gt;, wikipedia is impartial and will therefore provide a proper link (unlike Google)).&lt;/p&gt;
&lt;p&gt;Once I got access to the paper I will skim trough it to see if there is relevant information. If so I will make a copy to a paper folder and use Google scholar to generate the bibtex entry for me, there is a citation option at the bottom of the search result, click it and then bibtex. That little feature of Google scholar has already saved me probably several hours of making bibtex entries. The copied paper will have the same name as the bibtex entry key, this is important if you want to recheck your reference later again. Doing this will also lower the psychological barrier of re-checking something since you won’t have to go trough the entire obtain paper process again.&lt;/p&gt;
&lt;p&gt;Note that you shouldn’t track it in your version control, because first of all you don’t expect it to change, and second of all if you push it to a public repository you’re breaking the law on a whole other level. (distributing rather than just consuming, consuming is more easily ignored by law enforcement).&lt;/p&gt;
&lt;h2 id=&quot;books&quot;&gt;Books&lt;/h2&gt;
&lt;p&gt;I haven’t completely solved books. It seems that getting books is a lot more tougher than papers, probably because most scientist feel that papers should be easy obtainable but don’t necessarily feel for books the same way (many would have written one or contributed to one). I as a programmer feel very deeply about the necessity for freedom of information and therefore will share some possible sources. It will be up to the reader to decide if they should be using such sources. However do note that these sources aren’t always successful and you should prefer obtaining papers since sci-hub works practically always.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://gen.lib.rus.ec/&quot;&gt;library genesis&lt;/a&gt; should be your first source of books, it has a crappy interface and some mirrors may not work but if you get a result you usually also get a book.&lt;/p&gt;
&lt;p&gt;Then if that fails you can try and use IRC, which is described very thoroughly &lt;a href=&quot;https://www.reddit.com/r/Piracy/comments/2oftbu/guide_the_idiot_proof_guide_to_downloading_ebooks/&quot;&gt;here&lt;/a&gt;. But in short for archiving purposes, go to undernet, join bookz (/join #bookz) and then search for your book title (@search). Then if you get a result you need to save that file, which isn’t a book just the query result, open that and then if it contains your book use the code to download it.&lt;/p&gt;
&lt;p&gt;Finally there is a desperate method I used one time. It takes time but it can be worth the effort. There is this concept called digital borrowing, where HTML drm is used to ensure only &lt;em&gt;n&lt;/em&gt; copies get borrowed at a time. An example of such a website is the &lt;a href=&quot;https://openlibrary.org&quot;&gt;open library&lt;/a&gt;. The system is kind off dumb since making copies of digital stuff is practically free. However I do like the fact that some publishers fell for it. Anyway if it has your book you can just “borrow” it and make screen shots of each page. You just bypassed a bunch of HTML based drm and encryption with a button on your keyboard. Yes its pretty dumb. (not that I disliked the open library initiative or the internet archive, in fact I love there effort of tricking the publishers. There work may save some books from the copyright abyss, where literature gets lost forever because laws prevent copying before the last copy gets lost).&lt;/p&gt;
&lt;h1 id=&quot;time-management&quot;&gt;Time management&lt;/h1&gt;
&lt;p&gt;I have a pretty strict schedule by working 6 hours per day 5 days in the week. I won’t do any work on the thesis in the weekend. I only do 6 hours because personally I feel like those last two hours are usually wasted, only when I don’t notice the time pass by I will go overtime. I start every working day at 9 in the morning to about 3-ish. The days where I meet my teacher are of course the least productive. Currently this is on Wednesday, breaking up the week nicely.&lt;/p&gt;
&lt;p&gt;I do have to say that when I start there is no distraction. I will block websites such as Facebook, reddit and YouTube. 6 hours is a short time and the personal contract I have with my self is that this time will be used productively.&lt;/p&gt;
&lt;p&gt;Also note that annexing the weekend to try and finish the thesis a few weeks earlier is probably a bad idea. I mean focusing for extended amount of times on just one subject can only be done so long. The best I ever did was a commit streak on a hobby project on github for 3 weeks, and I had a lot of fun in making that. This probably won’t be true for all the work in your thesis. You may get burned out quickly if you try and do this. (Although I personally think it is quite a lot of fun to work on it.&lt;/p&gt;
&lt;h1 id=&quot;management&quot;&gt;&lt;span class=&quot;todo TODO&quot;&gt;TODO&lt;/span&gt; management&lt;/h1&gt;
&lt;p&gt;Tracking what stuff you have to do is rather quite important. What I’ve found most effective is a latex package called todonotes. it allows you to insert todo items in the document itself, which will be shown as long as your document class options are drafting, but as soon as you set it to final they will be removed from the final document.&lt;/p&gt;
&lt;p&gt;This integrates good with org, although misses any sort of highlighting. Org also doesn’t understand line breaks in todo items. Which makes it rather difficult to stay below 80 chars per line for todo items (this breaks my heart).&lt;/p&gt;
&lt;p&gt;I use the general todo items for feedback from the teacher and also for my own thoughts. Things I think I should do end up in a todo item, this allows the teacher to see what goes on in my mind and also if I understood his feedback correctly.&lt;/p&gt;
&lt;p&gt;Then with these notes I create some specialized commands:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode latex&quot;&gt;&lt;code class=&quot;sourceCode latex&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;bu&quot;&gt;\usepackage&lt;/span&gt;[obeyFinal, colorinlistoftodos]{&lt;span class=&quot;ex&quot;&gt;todonotes&lt;/span&gt;}&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;#cb1-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;\newcommand&lt;/span&gt;{&lt;span class=&quot;ex&quot;&gt;\drafting&lt;/span&gt;}{&lt;span class=&quot;fu&quot;&gt;\todo&lt;/span&gt;[noline, color=gray]{Working draft}}&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;#cb1-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;\newcommand&lt;/span&gt;{&lt;span class=&quot;ex&quot;&gt;\toReview&lt;/span&gt;}{&lt;span class=&quot;fu&quot;&gt;\todo&lt;/span&gt;[noline, color=yellow]{To review}}&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;#cb1-4&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;\newcommand&lt;/span&gt;{&lt;span class=&quot;ex&quot;&gt;\newlycleared&lt;/span&gt;}{&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;#cb1-5&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;\todo&lt;/span&gt;[noline, backgroundcolor=white, bordercolor=red]{Newly cleared}&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;#cb1-6&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;#cb1-7&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;\newcommand&lt;/span&gt;{&lt;span class=&quot;ex&quot;&gt;\cleared&lt;/span&gt;}{&lt;span class=&quot;fu&quot;&gt;\todo&lt;/span&gt;[noline, color=white]{Cleared}}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Drafting for paragraphs that are incomplete and should be finished. toReview for paragraphs that have been finished but should be checked again at a later time for spell/grammar reasons. newlycleared for the items that have been cleared but haven’t been seen by the teacher (he’s the guy giving me the grade, so gotta keep him on my side). Finally cleared for the items that should be done.&lt;/p&gt;
&lt;p&gt;Usually I build up a bunch of toReview items throughout the week and then go on a clearing spree the day before meeting the teacher. This also helps me reminding what I wrote about.&lt;/p&gt;
&lt;p&gt;Note that the idea of using todonotes I basically stole directly from one of my classmates. But this significantly made the quality of my documents better. Since I can manage my attention much more focused. Besides looking at the todo list and looking at the document have now become the same thing.&lt;/p&gt;
&lt;h1 id=&quot;in-short&quot;&gt;In short&lt;/h1&gt;
&lt;p&gt;This got way longer than I thought it would. I still even haven’t talked about editing tools, version control, org mode itself, and that awesome UML library called &lt;a href=&quot;http://plantuml.com/&quot;&gt;plantuml&lt;/a&gt; which integrates excellently with org. I will discuss these things in a later post. I hope these tips can be use full to you.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Deployment and todo&apos;s</title>
    <link href="https://jappieklooster.nl/deployment-and-todos.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2016-12-27:/deployment-and-todos.html</id>
    <published>2016-12-27T12:00:00Z</published>
    <updated>2016-12-27T12:00:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="meta"/>
    <summary type="html">&lt;p&gt;Yesterday I deployed the website, to my terror it wasn’t responsive on mobile devices (adapt to screensize). So with this post I fixed that, by replacing the basic font-size specifications from small to 1vw (everything else was em). The rest of the site already used percentages. The site needs to&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Yesterday I deployed the website, to my terror it wasn’t responsive on mobile devices (adapt to screensize). So with this post I fixed that, by replacing the basic font-size specifications from small to 1vw (everything else was em). The rest of the site already used percentages. The site needs to be responsive because its ironic to have a CGA based theme being responsive.&lt;/p&gt;
&lt;p&gt;So to deploy I found a vps partner in &lt;a href=&quot;https://galaxyhostplus.com/&quot;&gt;Galaxy Host Plus&lt;/a&gt;. They offer a vps package for about 2 euro 50 in the month I get 512MB of ram, 50GB of disk space 500GB of bandwidth and an IP address. This is a pretty good deal I think, took me about 2 hours to find (you can get a lot more expensive for less good specs, it should become cheaper every year). The domain name I had already registered at &lt;a href=&quot;https://www.starthosting.nl/&quot;&gt;Starhosting&lt;/a&gt;. Its 11 euro per year. So to make this site (self) sustainable I need to make at least &lt;span class=&quot;math display&quot;&gt;11/12 + 2.5 = 3.42&lt;/span&gt; euro per month. Although this is not completely fair since I’ll be using the vps for other stuff as well, such as Syncthing and private git (not for source code but just personal stuff, such as undeveloped ideas).&lt;/p&gt;
&lt;p&gt;To setup this website it took about 2 days to figure out both pelican and styling the theme. I could have done this a lot faster with wordpress or something but it wouldn’t have made me as happy as this theme and going full static website mode. Full static website mode scales a lot better than wordpress and is cheaper in maintenance (less band with, less memory used because no PHP or Apache). Besides, I already knew how to CSS, HTML, and more pure JS than would be considered healthy (yes I’ve done some native JS development, no libraries). Actually now I think about it I would’ve probably gotten lost in wordpress and for me it wouldn’t have been faster since I really wanted this theme.&lt;/p&gt;
&lt;p&gt;Lets talk about why I wanted this theme. First of all it fits me, I’m the kind of person who doesn’t care much for designs. Secondly I suspect its more memorable then a standard fashionable website with bootstrap. Thirdly I made it from the ground up (not the html structure, I sort off borrowed that, since I didn’t know how to pelican), which means its quite easy for me to change it. Fourthly I think there is a select group of people who like this theme, and those people probably also like what I have to say. Therefore the theme is practical.&lt;/p&gt;
&lt;h1 id=&quot;todo-list&quot;&gt;Todo list&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;+Scale mobile+ This is done now.&lt;/li&gt;
&lt;li&gt;HTTPS With lets encrypt around I probably should do this to please the security&lt;/li&gt;
&lt;li&gt;Add advertisements This is until my Patreon finally takes off&lt;/li&gt;
&lt;li&gt;Comment system. I have an idea for this, basically to make a reddit bot to auto create a thread for me and then link this that per post in this website with javascript. Shouldn’t be to hard, but probably a weekend of work (If anyone wants to help please contact me)&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Website Launch</title>
    <link href="https://jappieklooster.nl/website-launch.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2016-12-25:/website-launch.html</id>
    <published>2016-12-25T12:04:00Z</published>
    <updated>2016-12-25T12:04:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="meta"/>
    <summary type="html">&lt;p&gt;So this is the post where I’m launching this website. I finished the css mostly as a beautifull CGA theme. In this post I’ll discuss my decision making process.&lt;/p&gt;
&lt;h1 id=&quot;why-make-a-site&quot;&gt;Why make a site?&lt;/h1&gt;
&lt;p&gt;As an extension of my youtube account I will use this website, mostly for subjects I can’t&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;So this is the post where I’m launching this website. I finished the css mostly as a beautifull CGA theme. In this post I’ll discuss my decision making process.&lt;/p&gt;
&lt;h1 id=&quot;why-make-a-site&quot;&gt;Why make a site?&lt;/h1&gt;
&lt;p&gt;As an extension of my youtube account I will use this website, mostly for subjects I can’t make videos for. Either because of lack of time or because a video format just isn’t suited for it (for example when talking about a subject involving a bunch of shell commands, this site can be a place to put those commands). It can also be for themes that need to be well referenced (controversial opinions for example).&lt;/p&gt;
&lt;p&gt;The main purpose of this is to make money. I want to adopt a digital nomad like lifestyle (or something similar), and maintaining a website seems like a good addition. Currently I’m running this at a loss of course. Therefore I included advertisements on release and setup a patreon page. I need to make this work as soon as possible. However I also hate advertisements, therefore I make a promise to delete them as soon as patreon can cover the costs of running the website. By which I mean hosting costs (vps in my case) and domain name costs.&lt;/p&gt;
&lt;h1 id=&quot;site-setup&quot;&gt;Site setup&lt;/h1&gt;
&lt;p&gt;I use pelican to create this site. It is a script for parsing text based content formats and generate html from them, so that you don’t have to redefine the menu every blog post for example. So what happens it that you write your content in markdown, then you run the script which generates the static html for you. I tried setting up org, but had some problems so I’ll use markdown first, I think I can mix formats anyway.&lt;/p&gt;
&lt;p&gt;You can specify the structure of the html in the theme and of course the css. Note that even if the html is static you can still embed JavaScript, so you’re not committed to just static on each page. This is why I chose this tool. No commitments for the future and a relative simple setup. I’m thinking of later embedding a comment system (probably reddit), and macgyvering together a vote system, but this has to wait.&lt;/p&gt;
&lt;h2 id=&quot;the-theme&quot;&gt;The theme&lt;/h2&gt;
&lt;p&gt;The CGA theme was an intentional choice. My target audience is mainly people with interests in technical things, and I’m assuming that these kind of people will like such a theme either out of nostalgia or pragmatism.&lt;/p&gt;
&lt;p&gt;I got the inspiration from the Gentoo website they launched I think 2 years ago as an April fools joke, here is a screenshot:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/2016/gentoo-cga.png&quot; alt=&quot;gentoo cga&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;gentoo cga&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;!-- screenshot --&gt;
&lt;p&gt;(btw, if anyone has the original html implementation please contact me, I want to re-host it). I really loved the idea of just hosting a website like that. I had started working on a theme, using the kernel config as a style guide:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/2016/linux-config.png&quot; alt=&quot;kernel config&quot; /&gt; &lt;!-- screenshot --&gt;&lt;/p&gt;
&lt;p&gt;However I’ve been remarkably busy since that time (grad school, China internship etc), so I hadn’t come around finishing it. Untill now since I started writing my thesis, I’m realizing that soon I need to work, and I don’t really want to work for someone else.&lt;/p&gt;
&lt;p&gt;I like making CSS designs based of images, and I’m one of those oldtimers that doesn’t use anything fancy like less.js or bootstrap. So you can see here the result of my work. I may add some more art work in the future but I’m intending to use this theme for quite a while.&lt;/p&gt;
&lt;p&gt;Which brings us to another advantage of this theme, it will age very well. Unlike the newest fashion websites where people put huge images at the beginning of their posts and where you have to scroll endlessly to read something is this kind of theme tried and tested. I see the modern website industry becoming more like the fashion industry where practicality has to make way for beauty. I refuse to partake in such an “arms race”, redesigning my website every year or having to choose a picture every post seems just like a chore to me. If I want to add pictures to a post I’ll do it because I want to, not because its fashionable.&lt;/p&gt;
&lt;h2 id=&quot;no-cdns-fb-links-or-google-analytics&quot;&gt;No CDN’s FB links or google analytics&lt;/h2&gt;
&lt;p&gt;External requests to other domains significantly decrease page loading times. Don’t believe me? Well you can measure it yourself with your browser, it has an build-in network monitor (right click -&amp;gt; inspect element -&amp;gt; network, now press ctr+f5 and see what takes the longest to load, you can see most things go in parallel, but you should pay special attention to the things that go in sequence). Many page load speed improvement website actually recommend a CDN, which is stupid because laying the http connection to a CDN is much slower then just using the existing connection.&lt;/p&gt;
&lt;p&gt;But CDN’s aren’t meant to increase pageload, they’re meant to decrease serverload by moving parts of the static content delivery from the dynamic server to dedicated servers, freeing up server time and thus decreasing server load. But my entire website is static so why would I bother with that? server load is not going to be my bottleneck any time soon.&lt;/p&gt;
&lt;p&gt;When I browse the internet I use umatrix to block things such as google analytics and whatever the facebook requests do. Mainly out of privacy concerns but also because this speeds every website significantly, especially if you have a poor internet connection. Besides I don’t imagine my target audience uses facebook that much, correct me if I’m wrong.&lt;/p&gt;
&lt;h3 id=&quot;update-i-was-totally-wrong-about-cdns-at-least-for-fonts&quot;&gt;Update: I was totally wrong about CDN’s (at least for fonts)&lt;/h3&gt;
&lt;p&gt;I did some testing, and it turns out there are significant speed improvements for using a CDN. Ok you win this one, fonts.google.com. But I’m still not going to add those like buttons.&lt;/p&gt;
&lt;p&gt;Please do not that if you test this stuff that you have to press ctrl+f5 to tell the browser not to use a cache.&lt;/p&gt;
&lt;p&gt;See the difference in results below:&lt;/p&gt;
&lt;p&gt;Testing myself (from the Netherlands) &lt;img src=&quot;/images/2016/cdn-own-before.png&quot; alt=&quot;doing delivery from website (testing myself)&quot; /&gt; &lt;img src=&quot;/images/2016/cdn-own-after.png&quot; alt=&quot;doing delivery from cdn (testing myself)&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Testing with a test service configured from new york: &lt;img src=&quot;/images/2016/cdn-service-before.png&quot; alt=&quot;doing delivery from website (testing with service from newyork)&quot; /&gt; &lt;img src=&quot;/images/2016/cdn-service-after.png&quot; alt=&quot;doing delivery from cdn (testing with service form newyork)&quot; /&gt;&lt;/p&gt;
&lt;p&gt;From hong kong I got a ridiculous increase, from 3 seconds down to about 40ms. I don’t have a screenshot of that though (and to lazy to revert).&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Second post</title>
    <link href="https://jappieklooster.nl/second-post.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2016-12-24:/second-post.html</id>
    <published>2016-12-24T19:51:00Z</published>
    <updated>2016-12-24T19:51:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;p&gt;Yeah, I needed two actually to make sure everything looks good.&lt;/p&gt;
&lt;p&gt;So I guess I can type lots of information here.&lt;/p&gt;
&lt;p&gt;I wonder how long it will continue..&lt;/p&gt;
&lt;p&gt;Quite long acutually.&lt;/p&gt;
&lt;p&gt;Well, that’s fine. I’ll just think off more spaced out words!&lt;/p&gt;
&lt;p&gt;Damn I need to type so much before&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Yeah, I needed two actually to make sure everything looks good.&lt;/p&gt;
&lt;p&gt;So I guess I can type lots of information here.&lt;/p&gt;
&lt;p&gt;I wonder how long it will continue..&lt;/p&gt;
&lt;p&gt;Quite long acutually.&lt;/p&gt;
&lt;p&gt;Well, that’s fine. I’ll just think off more spaced out words!&lt;/p&gt;
&lt;p&gt;Damn I need to type so much before it will crop.&lt;/p&gt;
&lt;p&gt;Heheheh, this is cropped.&lt;/p&gt;
&lt;p&gt;Ok I guess this happens on word count. Or character, doesn’t really matter, at least not vertical space. Which I wondered and why I typed so much.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>First post</title>
    <link href="https://jappieklooster.nl/first-post.html" rel="alternate"/>
    <id>tag:jappieklooster.nl,2016-12-24:/first-post.html</id>
    <published>2016-12-24T19:43:00Z</published>
    <updated>2016-12-24T19:43:00Z</updated>
    <author>
      <name>Jappie J. T. Klooster</name>
    </author>
    <category term="reflection"/>
    <summary type="html">&lt;p&gt;So I’m trying to setup this website and to do this I need some filler text. Some people would make prommises about putting something up every week or so. But I don’t wanna do that because I hate chores, so this may as well be a huge waste of time.&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;So I’m trying to setup this website and to do this I need some filler text. Some people would make prommises about putting something up every week or so. But I don’t wanna do that because I hate chores, so this may as well be a huge waste of time.&lt;/p&gt;
&lt;h1 id=&quot;why-setup-a-site&quot;&gt;Why setup a site?&lt;/h1&gt;
&lt;p&gt;Because I’m oppinionated people.&lt;/p&gt;
&lt;h1 id=&quot;you-have-some-spell-error-over-hre&quot;&gt;You have some spell error over hre&lt;/h1&gt;
&lt;p&gt;Use the comment section to help fix any spell errors&lt;/p&gt;
&lt;h2 id=&quot;there-is-no-comment-section&quot;&gt;There is no comment section&lt;/h2&gt;
&lt;p&gt;Exactly. We must conclude that there are no spelling errors eiher.&lt;/p&gt;</content>
  </entry>
</feed>
