<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title></title>
    <link rel="self" type="application/atom+xml" href="https://fbrs.io/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://fbrs.io"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2025-07-19T00:00:00+00:00</updated>
    <id>https://fbrs.io/atom.xml</id>
    <entry xml:lang="en">
        <title>Getting a Raspberry Pi 5</title>
        <published>2025-07-19T00:00:00+00:00</published>
        <updated>2025-07-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://fbrs.io/rasp5/"/>
        <id>https://fbrs.io/rasp5/</id>
        
        <content type="html" xml:base="https://fbrs.io/rasp5/">&lt;p&gt;I bought a Raspberry Pi 5 because I wanted to run a temperature sensor. Mostly
so I can check how effective my portable air conditioning unit from DeLonghi
actually is in my apartment.&lt;&#x2F;p&gt;
&lt;p&gt;I naively assumed that v5 of the Pi (as opposed to my ancient v3) would support
video over USB-C, or at least have a standard USB-C port. I also assumed I
could just flash Home Assistant onto a USB stick and it would magically install
itself onto the SSD I got (together with the M.2 HAT).&lt;&#x2F;p&gt;
&lt;p&gt;My assumptions were all wrong.&lt;&#x2F;p&gt;
&lt;p&gt;It has a micro HDMI port (didn’t know that existed), USB-C is for power, and,
as far as I can tell, plugging in a USB stick won’t do anything.&lt;&#x2F;p&gt;
&lt;p&gt;So now I ordered a cable, a SD card, an SD card adapter, and I also added a SD
card reader for good measure. I now expect NOTHING to work, so I won’t assume
that my MacBook Pro’s SD card reader will work with these cards. Hence the USB
pluggable SD card reader.&lt;&#x2F;p&gt;
&lt;p&gt;I’m sure the Pi is great, but right now I just want to throw it in the trash.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;The idea is now to copy the standard Raspberry Pi image onto the SD card and
boot the Pi from that. Then SSH into it and use the imager tool to install Home
Assistant onto the SSD card. Finally, change the boot order so the SSD card
comes first.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;In the end I couldn’t wait for my SD card to arrive. I had to re-assemble my
old desktop computer anyway, before I could sell it. So I used the NVMe slot on
its mainboard to plugin the Rasperry Pi NVMe SSD, and used &lt;code&gt;rpi-imager&lt;&#x2F;code&gt; to
flash Home Assistant onto it.&lt;&#x2F;p&gt;
&lt;p&gt;The Pi immediately booted from the NVMe, without having to change anything in
the boot order.&lt;&#x2F;p&gt;
&lt;p&gt;It then took me a while to realize that my old, crappy ethernet cable was
constantly wiggling itself loose, resulting in a lost connection to the HA web
interface.&lt;&#x2F;p&gt;
&lt;p&gt;Then I tried to setup my ConBee 3 stick. The web updater gave me an error (of
course), and the &lt;code&gt;GCFFlasher&lt;&#x2F;code&gt; tool in NixOS is some minor versions behind and
also didn’t work. It took me a while to realize that that was the case. I then
had to compile it from scratch. &lt;a href=&quot;https:&#x2F;&#x2F;devenv.sh&#x2F;&quot;&gt;devenv&lt;&#x2F;a&gt; came in very
handy. I was in a hurry and had no intention to figure out how to setup a C
environment. So I just did &lt;code&gt;devenv init&lt;&#x2F;code&gt; and set &lt;code&gt;languages.cplusplus.enable&lt;&#x2F;code&gt;
to true. Worked flawlessly.&lt;&#x2F;p&gt;
&lt;p&gt;Now my sensor is finally connected. It’s 27 degrees Celsius in my bed room,
apparently.&lt;&#x2F;p&gt;
&lt;p&gt;What an adventure.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Advent of Code 2024 Day 6: Janet Streams Using Fibers&#x2F;Coroutines</title>
        <published>2024-12-07T00:00:00+00:00</published>
        <updated>2024-12-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://fbrs.io/aoc2024-d6/"/>
        <id>https://fbrs.io/aoc2024-d6/</id>
        
        <content type="html" xml:base="https://fbrs.io/aoc2024-d6/">&lt;p&gt;Remember when it was all the rage to write articles about functional programming (FP) in Javascript by explaining how you can chain &lt;code&gt;.map&lt;&#x2F;code&gt;, &lt;code&gt;.filter&lt;&#x2F;code&gt; and &lt;code&gt;.reduce&lt;&#x2F;code&gt; on lists? I hated that. I think that it conditions people into thinking that FP is all about list comprehensions. And when lists aren’t convenient anymore (more on this later), they then resort to imperative programming, thinking that FP isn’t suited to that kind of task.&lt;&#x2F;p&gt;
&lt;p&gt;In Advent of Code (AoC) there are plenty of examples where eager list comprehensions won’t get you very far. An innocent looking &lt;code&gt;map().filter().map()&lt;&#x2F;code&gt; can consume all your memory and make the garbage collector go crazy if you are creating and re-creating huge lists. A straight forward solution, as I mentioned earlier, is to fall back to more imperative patterns, such as the &lt;code&gt;loop&lt;&#x2F;code&gt; macro in Janet.&lt;&#x2F;p&gt;
&lt;p&gt;I was hoping that I could use Janet’s fibers&#x2F;coroutines in combination with its stdlib &lt;code&gt;map&lt;&#x2F;code&gt; and &lt;code&gt;filter&lt;&#x2F;code&gt; function to work on streams rather than eagerly evaluated lists. But that was not the case:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;janet&quot; class=&quot;language-janet &quot;&gt;&lt;code class=&quot;language-janet&quot; data-lang=&quot;janet&quot;&gt;(-&amp;gt;&amp;gt; (gen-stuff input)
     (map foo)
     (filter bar))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In my testing on AoC day 6 (the first one where you walk around in a grid), the imperative version using &lt;code&gt;loop&lt;&#x2F;code&gt; used about 80MB, the version that kicks things off with a generator and then runs this through various list comprehenions immediately took up around 10GB of memory. Here’s a concrete example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;janet&quot; class=&quot;language-janet &quot;&gt;&lt;code class=&quot;language-janet&quot; data-lang=&quot;janet&quot;&gt;(defn gen-nums [] (coro (for i 0 10000000 (yield i)))

(comment
  # low mem usage
  (each v (gen-nums) (print v))

  # high mem usage
  (each v (map |(string&amp;#x2F;repeat (string $) 100) (gen-nums)) (print v)))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But it turns out that it is surprisingly straight forward to have your cake and eat it too. You can use easily define streaming versions of &lt;code&gt;map&lt;&#x2F;code&gt; and &lt;code&gt;filter&lt;&#x2F;code&gt; using the &lt;code&gt;coro&lt;&#x2F;code&gt; function (or macro?):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;janet&quot; class=&quot;language-janet &quot;&gt;&lt;code class=&quot;language-janet&quot; data-lang=&quot;janet&quot;&gt;(defn map* [f ds] (coro (each v ds (yield (f v)))))

(defn filter* [f ds] (coro (each v ds (when (f v) (yield v)))))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I’ve used these for an upated implementation of day 6, which you can find &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cideM&#x2F;aoc2024-janet&#x2F;blob&#x2F;main&#x2F;d6&#x2F;main.janet#L52-L58&quot;&gt;here&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Advent of Code 2024 Day 2: Parsing Expression Grammars</title>
        <published>2024-12-02T08:08:55+00:00</published>
        <updated>2024-12-02T08:08:55+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://fbrs.io/aoc2024-d2/"/>
        <id>https://fbrs.io/aoc2024-d2/</id>
        
        <content type="html" xml:base="https://fbrs.io/aoc2024-d2/">&lt;p&gt;I am fully committed to using Janet this year! At least I hope so. One of my goals is to get really familiar and fluent with using parsing expression grammars (PEG). I’ve always liked parser combinators, which seem to be more or less the same thing. One of the most basic and typical ways to parse input in Advent of Code is to split a string into a lines and split each line on spaces.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;text&quot; class=&quot;language-text &quot;&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;1 2 3
4 5 6
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This an be achieved quite elegantly with a somewhat more recent addition to the PEG library, &lt;code&gt;split&lt;&#x2F;code&gt;. You give it two patterns, one for the separator and one for the actual contents, and it generally does the right thing. There is just one caveat. In the following snippet, there’s a space at the end of my input string. If you remove the asterisk &lt;code&gt;*&lt;&#x2F;code&gt; from the digit pattern, you get no matches. So &lt;code&gt;split&lt;&#x2F;code&gt; more or less requires you to make the content optional, unless you are absolutely certain that you won’t have a dangling separator at the end of your input.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;janet&quot; class=&quot;language-janet &quot;&gt;&lt;code class=&quot;language-janet&quot; data-lang=&quot;janet&quot;&gt;  (peg&amp;#x2F;match ~(split :s &amp;#x27;:d*) &amp;quot;1 2 3 &amp;quot;)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;By making the second pattern optional, the end of the string, “3 “ can now be matched as two digits separated by a space. The second digit is simply empty. Sounds totally logical, I know. But you probably don’t want an empty capture. You can either remove it later through &lt;code&gt;filter&lt;&#x2F;code&gt; or you can call &lt;code&gt;string&#x2F;trimr&lt;&#x2F;code&gt; on the input, which is my convention for AoC. This removes trailing whitespace, so you no longer need to make the second pattern optional, like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;janet&quot; class=&quot;language-janet &quot;&gt;&lt;code class=&quot;language-janet&quot; data-lang=&quot;janet&quot;&gt;(peg&amp;#x2F;match ~(split :s &amp;#x27;:d) (string&amp;#x2F;trimr &amp;quot;1 2 3 &amp;quot;))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Of course you’ll have to adjust your code for other separators (or &lt;code&gt;filter&lt;&#x2F;code&gt; it out later).&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, back to the real world (of AoC). Here’s the same PEG with and without using &lt;code&gt;split&lt;&#x2F;code&gt;. I think it’s a huge improvement.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;janet&quot; class=&quot;language-janet &quot;&gt;&lt;code class=&quot;language-janet&quot; data-lang=&quot;janet&quot;&gt;# before
(def input-peg
  (peg&amp;#x2F;compile
    ~{:main (* (some (* :line (? :s))) -1)
      :line (group (some (* :num (any &amp;quot; &amp;quot;))))
      :num (&amp;#x2F; (&amp;lt;- :d+) ,scan-number)}))

# after
(def parser
  (peg&amp;#x2F;compile ~(split &amp;quot;\n&amp;quot; (group (split :s (any (number :d+)))))))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Dark&#x2F;Light Switching for the Terminal</title>
        <published>2024-10-09T00:00:00+00:00</published>
        <updated>2024-10-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://fbrs.io/dark-mode-shell/"/>
        <id>https://fbrs.io/dark-mode-shell/</id>
        
        <content type="html" xml:base="https://fbrs.io/dark-mode-shell/">&lt;p&gt;I firmly believe that you should use light mode when the ambient lighting is bright. As far as I know, science agrees with that, since dark text on a white background is easier to read than the opposite.&lt;&#x2F;p&gt;
&lt;p&gt;But after the sun has set and you’ve dimmed all the lights, staring at a bright screen seems wrong and it looks out of place when the rest of your system switches to dark mode.&lt;&#x2F;p&gt;
&lt;p&gt;For the longest time I’ve therefore wanted to have the automatic dark&#x2F;light mode switching in my terminal environment, which consists of Alacritty, tmux, Fish and Neovim (tmux doesn’t define any color values of its own, so we can ignore it).&lt;&#x2F;p&gt;
&lt;p&gt;I finally got around to spending some time on this not so tricky problem and I’d say I’m 85% there. I use my &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cideM&#x2F;yui&quot;&gt;own color theme&lt;&#x2F;a&gt; which exports config files for, among other things, all three programs listed above. And all config files are available in a dark and a light mode. Meaning, in Neovim I can simply switch to the dark version with &lt;code&gt;:color yui_dark&lt;&#x2F;code&gt;. Since Neovim has a nice client&#x2F;server architecture I can also do this remotely:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;text&quot; class=&quot;language-text &quot;&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;:let g:lightline.colorscheme = &amp;quot;yui_dark&amp;quot;
    \ | colorscheme yui_dark
    \ | call lightline#init()
    \ | call lightline#colorscheme()
    \ | call lightline#update()&amp;lt;CR&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Alacritty also has a nice API for changing config values from the shell. You can read more about it under &lt;code&gt;man alacritty-msg&lt;&#x2F;code&gt; (and &lt;code&gt;man 5 alacritty&lt;&#x2F;code&gt; for the config values) but the gist is &lt;code&gt;alacritty msg config -w -1 &#x27;colors.cursor.background=&quot;#CCCCCC&quot;&#x27;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Lastly, for configuring the Fish shell syntax colors you use shell commands anyway, so the exported “config” is a Fish file that I can call whenever I want. The file has commands like this:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;set fish_color_match eae9e9
set fish_color_selection --background=474355
set fish_color_search_match --background=4f4b5f
...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In other words: I now have shell commands for remotely changing Alacritty, Fish and Neovim from light to dark mode and vice versa. The “only” thing left to do is to find a way of running either of the two variants when the system switches themes.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Heist: Haskell Templating Woes</title>
        <published>2023-08-31T00:00:00+00:00</published>
        <updated>2023-08-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://fbrs.io/heist-2/"/>
        <id>https://fbrs.io/heist-2/</id>
        
        <content type="html" xml:base="https://fbrs.io/heist-2/">&lt;p&gt;Yesterday I got my feet wet by rendering a single, measly splice. And at first it didn’t look like I’d even accomplish that before the end of the day. Today I want to extend the example by adding more splices that operate on different data. In the &lt;a href=&quot;http:&#x2F;&#x2F;snapframework.com&#x2F;docs&#x2F;tutorials&#x2F;compiled-splices&quot;&gt;compiled splices tutorial&lt;&#x2F;a&gt; they have an example that shows how to render a list of persons. But in a real world application with dozens of routes you will have dozens of splices that all require different data. But if all of those compiled splices end up in your Heist state under a single type, would that type end up being the concatentation of all the parameters of all splices? Let’s find out.&lt;&#x2F;p&gt;
&lt;p&gt;The goal for today is this: Make a (fake) database call and use the data to generate two splices, one for a &lt;code&gt;Text&lt;&#x2F;code&gt; and one for an &lt;code&gt;Int&lt;&#x2F;code&gt;, that are then used in a template.&lt;&#x2F;p&gt;
&lt;p&gt;I specifically do not want to create some application monad and access it from within splices. My major concern with this is that individual splices are now free to make database calls, much like a GraphQL API where each field is backed by an independent resolver, which can make as many database calls as it wants. I’m actually not a fan of this application monad pattern, because it makes it all too easy to have code access your logger or your database that really shouldn’t.&lt;&#x2F;p&gt;
&lt;p&gt;Here’s how I imagine this will work in pseudo-code:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;main = do
  data &amp;lt;- fakeDatabaseCall
  heistState &amp;lt;- initHeist { ... }

  let spliceA = genSpliceA (data.someNumber)
  let spliceB = genSpliceB (data.someText)

  heistState.splices = heistState.splices
    &amp;#x2F;&amp;#x2F; { spliceA = spliceA, spliceB = spliceB }

  renderTemplate heistState &amp;quot;foo&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I suspect that merging splices into the Heist state will be a major undertaking. I have no idea how I can modify Heist state. Indeed, the documentation for &lt;code&gt;initHeist&lt;&#x2F;code&gt; says this:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;We don’t provide functions to add either type of loadtime splices to your HeistState after initHeist because it doesn’t make any sense unless you re-initialize all templates with the new splices.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The documentation does mention&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Heist’s HeistState -&amp;gt; HeistState “filter” functions.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;but I don’t know where they are. They do have a few functions that all work in the &lt;code&gt;HeistT n m ()&lt;&#x2F;code&gt; environment, but I don’t know how I would use them. I could call &lt;code&gt;modifyHS&lt;&#x2F;code&gt; in a splice function, but then I’m once again in a load-time splice function and I want to avoid the whole runtime stuff-everything-into-an-application monad.&lt;&#x2F;p&gt;
&lt;p&gt;So I guess modifying the Heist state is not an option after all. What else can I do then, that’s not the giant-all-encompassing-application-monad-of-doom? The tutorial code has this snippet in it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;hs &amp;lt;- load baseDir (&amp;quot;people&amp;quot; ## allPeopleSplice)
let runtime = fromJust $ C.renderTemplate hs &amp;quot;people&amp;quot;
builder &amp;lt;- evalStateT (fst runtime)
            [ Person &amp;quot;John&amp;quot; &amp;quot;Doe&amp;quot; 42
            , Person &amp;quot;Jane&amp;quot; &amp;quot;Smith&amp;quot; 21
            ]
return $ toByteString builder
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice that they’re supplying the data for this view through a simple, hard coded state monad. I could create runtime splices that use a bespoke reader monad and then in my route handlers fill that reader monad with all the data for that route. I suspect that this will hamper re-use though. If you have a splice that needs an int and its used in two different templates that use a different reader monad each, then I can think of two options:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;duplicate the splice&lt;&#x2F;li&gt;
&lt;li&gt;make the splice a bit more generic with a type class and then implement that type class for each monad&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;class HasNewsCount a where
  getNewsCount :: a -&amp;gt; Int

instance HasNewsCount ViewA where
  getNewsCount = undefined

instance HasNewsCount ViewB where
  getNewsCount = undefined
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Anyway, let’s give this a try. First, I need a somewhat more realistic example. I created two views for two routes:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;xml&quot; class=&quot;language-xml &quot;&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&amp;#x2F;&amp;#x2F; view_a.tpl
&amp;lt;apply template=&amp;quot;index&amp;quot;&amp;gt;
  &amp;lt;person &amp;#x2F;&amp;gt;
  &amp;lt;foo &amp;#x2F;&amp;gt;
&amp;lt;&amp;#x2F;apply&amp;gt;

&amp;#x2F;&amp;#x2F; view_b.tpl
&amp;lt;apply template=&amp;quot;index&amp;quot;&amp;gt;
  &amp;lt;count &amp;#x2F;&amp;gt;
  &amp;lt;foo &amp;#x2F;&amp;gt;
&amp;lt;&amp;#x2F;apply&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;They both have &lt;code&gt;&amp;lt;foo &#x2F;&amp;gt;&lt;&#x2F;code&gt; in common, so that I can go through the use case of having a shared splice that gets its data from different reader monads (unless I figure out a solution that doesn’t need those monads, but I doubt it). They also each have a splice that’s exclusive to the view, so that the data for each view as a whole is different.&lt;&#x2F;p&gt;
&lt;p&gt;I cleaned up &lt;code&gt;main.hs&lt;&#x2F;code&gt; which now looks like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;mainSplices :: Monad m =&amp;gt; Splices (C.Splice m)
mainSplices = return mempty

main :: IO ()
main = do
  let spliceConfig =
        mempty
          &amp;amp; scLoadTimeSplices .~ defaultLoadTimeSplices
          &amp;amp; scTemplateLocations .~ [loadTemplates &amp;quot;app&amp;quot;]

  eitherHeistState &amp;lt;-
    initHeist $
      emptyHeistConfig
        &amp;amp; hcNamespace .~ &amp;quot;&amp;quot;
        &amp;amp; hcErrorNotBound .~ False
        &amp;amp; hcSpliceConfig .~ spliceConfig
        &amp;amp; hcCompiledSplices .~ mainSplices

  case eitherHeistState of
    Left err -&amp;gt;
      putStrLn $ &amp;quot;Heist init failed: &amp;quot; ++ show err
    Right heistState -&amp;gt; do
      case C.renderTemplate heistState &amp;quot;view_a&amp;quot; of
        Nothing -&amp;gt; do
          putStrLn &amp;quot;Index not found!&amp;quot;
        Just (docRuntime, _) -&amp;gt; do
          docBuilder &amp;lt;- docRuntime
          print $ toByteString docBuilder
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I’m already scared of this &lt;code&gt;Monad m =&amp;gt; Splices (C.Splice m)&lt;&#x2F;code&gt; being my downfall. This &lt;code&gt;m&lt;&#x2F;code&gt; will have to be specialized to an appropriate reader monad for each view. But without having it be the amalgamation of all views (or their data).&lt;&#x2F;p&gt;
&lt;p&gt;And just as I thought, this doesn’t work. In retrospect it’s rather obvious.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;fooSplice :: (MonadIO m, MonadReader e m, HasFoo e) =&amp;gt; C.Splice m
fooSplice = do
  return $ C.yieldRuntimeText $ do
    fooValue &amp;lt;- lift $ asks foo
    return $ T.pack $ show fooValue
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you build a few splices like that, all with a different &lt;code&gt;Has*&lt;&#x2F;code&gt; constraint, the top level splices list must gather up all those constraints.&lt;&#x2F;p&gt;
&lt;p&gt;Recapping:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;modifying the list of splices after &lt;code&gt;initHeist&lt;&#x2F;code&gt; seems hard and not what you’re supposed to do&lt;&#x2F;li&gt;
&lt;li&gt;any concrete type in a splice will bubble up to the top level splices definition, where you’ll be forced to have a type that is the concatenation of all child types&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I took another look at the &lt;a href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;8023191&#x2F;using-values-not-from-the-application-monad-with-heist-templates&quot;&gt;Stack Overflow answer&lt;&#x2F;a&gt; here and specifically looked at the source code mentioned in a comment. But that source code seems to reference a Heist version that is practically ancient at this point. I don’t think the option mentioned by “mightybyte” is viable anymore.&lt;&#x2F;p&gt;
&lt;p&gt;I updated the example repository at &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cideM&#x2F;heist_getting_started&#x2F;tree&#x2F;498e072a9aab8f06b1d7a3f4601e5062198e1b57&quot;&gt;this commit&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Next I’ll have to figure out which other templating library I can use or if I want to just drop Haskell for this project.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Two Years of Nix &amp; Home Manager</title>
        <published>2023-06-05T00:00:00+00:00</published>
        <updated>2023-06-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://fbrs.io/nix-hm-reflections/"/>
        <id>https://fbrs.io/nix-hm-reflections/</id>
        
        <content type="html" xml:base="https://fbrs.io/nix-hm-reflections/">&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;After utilizing Nix and HM to manage both a MacOS and a NixOS
machine for a solid two years, I can confidently say that the experience
has been incredibly pleasant overall. Reflecting back, the major
advantages that stood out, and continue to do so, include:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Seamless project environment management with
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;nix-direnv&quot;&gt;&lt;code&gt;nix-direnv&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, which, in
my opinion, is unmatched.&lt;&#x2F;li&gt;
&lt;li&gt;Having a single package manager instead of one for each application.
This not only simplifies package management but also enables upgrading
everything with just a single command. Nix has effectively replaced
the following plugin&#x2F;package managers for me:
&lt;ul&gt;
&lt;li&gt;Neovim plugins&lt;&#x2F;li&gt;
&lt;li&gt;Fish shell plugins&lt;&#x2F;li&gt;
&lt;li&gt;System packages (for example AUR, MacPorts)&lt;&#x2F;li&gt;
&lt;li&gt;tmux plugins&lt;&#x2F;li&gt;
&lt;li&gt;Language package managers (npm, cargo, and so on)&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Visual Studio Code plugins&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;At one point, I briefly reverted back to using only MacPorts and a basic
dotfiles repository. I questioned whether the added complexity of Nix
and HM was truly worth it. But without the integration between
&lt;code&gt;nix-direnv&lt;&#x2F;code&gt; and my shell, switching between projects became a chore.
Upgrading packages now meant interacting with multiple, different upgrade
processes instead of just a single command. Plus, if I ever decide
to upgrade my desktop computer and go back to Linux, I’ll have to
painstakingly sync both setups manually.&lt;&#x2F;p&gt;
&lt;p&gt;If you’re content with your current setup, then the effort of learning
Nix might not outweigh its benefits.&lt;&#x2F;p&gt;
&lt;p&gt;However, if you see room for improvement, I strongly recommend exploring
Nix.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-worked-well&quot;&gt;What worked well&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;unparalleled-reliability&quot;&gt;Unparalleled Reliability&lt;&#x2F;h3&gt;
&lt;p&gt;If you’re someone who enjoys tinkering with Linux, then in my opinion,
there’s simply no better alternative to NixOS. The ability to replace
your boot loader, shell, Kernel parameters, and practically anything you
want, reboot, and effortlessly revert back to the previous state of
your system is an absolute superpower. It eradicates any fear of having
to troubleshoot issues from a rescue USB stick, thereby empowering you
to boldly experiment. The same level of confidence extends to system
updates as well. I can’t recall a single instance where I was unable to
use my NixOS system.&lt;&#x2F;p&gt;
&lt;p&gt;Another aspect I appreciate is how NixOS configuration options often go
beyond merely mirroring the configuration of the underlying software in
a one-to-one manner. Take, for instance, enabling wireplumber, which not
only modifies files in &lt;code&gt;&#x2F;etc&#x2F;&lt;&#x2F;code&gt; but also adds a
&lt;code&gt;DBUS_SESSION_BUS_ADDRESS&lt;&#x2F;code&gt; environment variable, and so on. Another
example is enabling &lt;code&gt;bspwm&lt;&#x2F;code&gt;, a tiling window manager. Setting just
&lt;code&gt;bspwm.enable = true;&lt;&#x2F;code&gt; will install the package and add &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;NixOS&#x2F;nixpkgs&#x2F;blob&#x2F;nixos-unstable&#x2F;nixos&#x2F;modules&#x2F;services&#x2F;x11&#x2F;window-managers&#x2F;bspwm.nix&quot;&gt;xserver
configuration&lt;&#x2F;a&gt;
that also gets rid of some annoying issues in certain Java GUI
applicatoins. This relieves me from meticulously keeping track of
interactions between various services and tools. NixOS generally strikes
a good balance between making these options genuinely useful while not
having too many unexpected consequences. Ultimately, the ability to
enable something and have it reliably do the right thing is something I
really came to appreciate.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;effortless-configuration-sharing&quot;&gt;Effortless Configuration Sharing&lt;&#x2F;h3&gt;
&lt;p&gt;Sharing configuration between MacOS and NixOS has been very straight
forward overall. My approach is to have a &lt;code&gt;.nix&lt;&#x2F;code&gt; file to consolidate
shared packages and configuration. This file is then imported into the
host-specific &lt;code&gt;home.nix&lt;&#x2F;code&gt; file, which can include additional packages and
configuration specific to each host. To illustrate, here are two code
snippets demonstrating how to integrate tmux with the system clipboard
on each respective platform. Both snippets are merged with the shared
tmux configuration (in this case by simply appending the strings to the
end of the shared configuration).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;# NixOS
{
  programs.tmux.extraConfig = &amp;#x27;&amp;#x27;
    bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel &amp;quot;${pkgs.xsel}&amp;#x2F;bin&amp;#x2F;xsel -i --clipboard&amp;quot;
  &amp;#x27;&amp;#x27;;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;# MacOS
{
  programs.tmux.extraConfig = &amp;#x27;&amp;#x27;
    bind-key -T copy-mode-vi y send -X copy-pipe-and-cancel &amp;quot;pbcopy&amp;quot;
  &amp;#x27;&amp;#x27;;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;project-environments-with-nix-direnv&quot;&gt;Project Environments With &lt;code&gt;nix-direnv&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;One of the features I really missed when attempting to go back to a
simpler setup was the ability to seamlessly switch between different
work repositories. Each repository often required a distinct set of
tools, such as varying NodeJS versions, language toolchains, database
clients, S3 tools, and so on. Even in 2023, it appears that efficiently
managing this is still an unsolved &lt;del&gt;mystery&lt;&#x2F;del&gt; problem.&lt;&#x2F;p&gt;
&lt;p&gt;You can put all of these things in a Docker container but to be honest,
I have never found developing through a Docker container a pleasant
experience. So in the end, at last at $DAY_JOB, we have Docker
containers to run the actual software either locally or in production,
but the development environment itself is something every developer
handles differently. Most people rely on a mix of global tools that
hopefully don’t conflict and a gazillion version managers.&lt;&#x2F;p&gt;
&lt;p&gt;What I do is create a repository that has a single &lt;code&gt;flake.nix&lt;&#x2F;code&gt; file. In
that file, I define “development shells” for each project, like so:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;{
  shared = [
    google-cloud-sdk
    kubectl # pinned to a specific version
    aws-mfa
  ];

  project1 = {
    buildInputs = [
      go
      go-migrate pgformatter
      gopls
      go-tools
      golangci-lint
      go-outline
      gopkgs
      delve
    ];
  };

  project2 = {
    buildInputs = [
      nodePackages.typescript-language-server
      nodePackages.prettier
    ];
  };
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In every project directory, I then add a &lt;code&gt;.envrc&lt;&#x2F;code&gt; file, where I tell
&lt;code&gt;nix-direnv&lt;&#x2F;code&gt; to &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;nix-direnv#flakes-support&quot;&gt;use one of those development
environments&lt;&#x2F;a&gt; with
a simple one-liner like this: &lt;code&gt;use flake &#x2F;path&#x2F;to&#x2F;flake#project&lt;&#x2F;code&gt;. I can also
put other code in that &lt;code&gt;.envrc&lt;&#x2F;code&gt; file&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, but that’s not really different from
using the non-nix version of &lt;code&gt;direnv&lt;&#x2F;code&gt;. Whenever I enter one of those
directories, my shell magically has the tools I specified for that project
available on &lt;code&gt;PATH&lt;&#x2F;code&gt;. This works with different shells (I use Fish for example).&lt;&#x2F;p&gt;
&lt;p&gt;In other words:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;shell&quot; class=&quot;language-shell &quot;&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;$ which go
$ cd my_project&amp;#x2F;
$ which go
&amp;#x2F;nix&amp;#x2F;store&amp;#x2F;rhmf86rrq5sksqhg1544dq6hvxrr5cvg-go-1.20.4&amp;#x2F;bin&amp;#x2F;go
$ cd ~
$ which go
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I can not live without this feature anymore. The combination of
effortlessly having per-project tools and being able to maintain those
environments in a different repository if needed (so your coworkers
don’t need to know about Nix), is just so good! Even if you don’t want
to use &lt;code&gt;nix-direnv&lt;&#x2F;code&gt; I really encourage you to look at the non-Nix
version of &lt;a href=&quot;https:&#x2F;&#x2F;direnv.net&#x2F;&quot;&gt;&lt;code&gt;direnv&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;simple-but-not-easy&quot;&gt;Simple but not Easy&lt;&#x2F;h3&gt;
&lt;p&gt;According to &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=LKtk3HCgTa8&quot;&gt;Rich Hickey&lt;&#x2F;a&gt;,
the distinction between “easy” and “simple” lies in the level of effort
and complexity involved. “Easy” implies something intuitive and
effortless initially but can lead to increasing complexity in the long
run. On the other hand, “simple” requires more upfront investment but
results in overall reduced complexity. This is how I’ll be using these
terms in this chapter.&lt;&#x2F;p&gt;
&lt;p&gt;Recently, I contributed two packages to the MacPorts package repository.
While the onboarding process was considerably easier compared to Nix, it
didn’t take long until I encountered issues related to leftover build
artifacts. Each build would yield different output, with the first build
often returning errors that didn’t appear in subsequent ones. To address
this, I resorted to deleting certain folders containing build-related
files, hoping to restore a clean build environment. In other words, it
was easy to get started but difficult to reach a comprehensive
understanding of what’s actually going on.&lt;&#x2F;p&gt;
&lt;p&gt;With Nix on the other hand, the first steps are anything but intuitive.
Nix is a functional programming language, which in itself can be quite
demanding. Because it is used in so many different areas&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;,
documentation is often abstract. There’s no such thing as a “definitive
10-step guide for managing your home folder with Nix” in the official
manual. Compare this to MacPorts, which has a much narrower focus, and
as such the documentation can be a lot more specific and hands-on.&lt;&#x2F;p&gt;
&lt;p&gt;However, Nix also embodies a sense of simplicity: same input, same
output. This concept is tremendously powerful and empowering. It enables
a highly motivating edit-compile feedback loop. I believe it is this
simplicity that led me to contribute to Nixpkgs, making it the first
package repository I ever contributed to.&lt;&#x2F;p&gt;
&lt;p&gt;Undoubtedly, certain aspects of Nix can be challenging. For instance,
dealing with dependencies in JavaScript and Python applications can be
incredibly messy. I’ve come to really hate Javascript’s &lt;code&gt;postInstall&lt;&#x2F;code&gt;
scripts, which serve as an escape hatch allowing arbitrary actions
during a build. They are often used to install binaries that are then
called by the Javascript code of that package. Consequently, some
packages incorporate a makeshift, ad-hoc package manager that determines
the platform, downloads a binary, and places it in the hopefully correct
location. However Nix doesn’t allow network requests in its build
sandbox. Therefore, getting such Javascript packages to play nicely with
Nix can be a challenge.&lt;&#x2F;p&gt;
&lt;p&gt;And that’s just one example. In general, the more complex and messy the
packaging process, the greater the difficulty in making it work
seamlessly with Nix.&lt;&#x2F;p&gt;
&lt;p&gt;But I believe that the eventual simplicity of Nix is often (not always)
worth the initial cost.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;streamlined-package-management&quot;&gt;Streamlined Package Management&lt;&#x2F;h3&gt;
&lt;p&gt;When I switched from Nix to MacPorts, it became evident how many package
managers I relied on:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;MacPorts&lt;&#x2F;li&gt;
&lt;li&gt;Fish plugin manager&lt;&#x2F;li&gt;
&lt;li&gt;Vim&#x2F;Neovim plugin manager&lt;&#x2F;li&gt;
&lt;li&gt;Visual Studio Code plugin manager&lt;&#x2F;li&gt;
&lt;li&gt;tmux plugin manager&lt;&#x2F;li&gt;
&lt;li&gt;NPM or Yarn&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;However, with Nix and HM, I can consolidate all of these into
just Nix. This means I have a single command to update all my packages
across all my tools, a single command to install everything on a new
machine, and a unified set of concepts and knowledge applicable to all
my packaging needs.&lt;&#x2F;p&gt;
&lt;p&gt;How much this matters to you depends on how many package and plugin
managers you use right now. How well they work, how often you need to
fiddle with what they do. Many of my colleagues are content with using
an IntelliJ IDE and Homebrew, and that works perfectly well for them.&lt;&#x2F;p&gt;
&lt;p&gt;There is one aspect of this I want to emphasize. Even though Nixpkgs is already
one of the biggest package repositories out there, I occasionally come across
missing packages. For instance, as of writing this article,
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ojroques&#x2F;nvim-lspfuzzy&quot;&gt;&lt;code&gt;ojroques&#x2F;nvim-lspfuzzy&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; is not
part of Nixpkgs. In the absence of Nix, I would have resorted to manually
cloning the repository and placing the files in the appropriate directories (or
install a Neovim plugin manager). However, with Nix, I can leverage the power
of &lt;em&gt;overlays&lt;&#x2F;em&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;(self: super: {
  vimPlugins =
    super.vimPlugins
    &amp;#x2F;&amp;#x2F; {
      lspfuzzy = super.pkgs.vimUtils.buildVimPluginFrom2Nix rec {
        version = &amp;quot;latest&amp;quot;;
        pname = &amp;quot;lspfuzzy&amp;quot;;
        src = lspfuzzy;
      };
    };
})
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Applying this overlay to the Nix package set allows me to introduce a
new package called nix-env-fish into my locally available packages. It
works as a form of dependency injection, seamlessly integrating into my
configuration as if it were a part of Nixpkgs itself. The fact that it’s
added through an overlay doesn’t matter.&lt;&#x2F;p&gt;
&lt;p&gt;Overlays are a bit like a gateway drug into authoring your own packages.
They let you quickly experiment with something locally, while still
using the infrastructure of Nixpkgs. Once your overlay is stable, it’s
easy to convert it into a standalone package and create a pull request.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-didnt-work-so-well&quot;&gt;What didn’t work so well&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;missing-or-broken-gui-apps&quot;&gt;Missing or Broken GUI Apps&lt;&#x2F;h3&gt;
&lt;p&gt;At times, certain GUI apps on NixOS would simply display a black screen.
This issue appeared to be specific to Electron-based applications,
although I never found the motivation to debug these problems. On MacOS,
I faced another limitation as not all the GUI apps I wanted to install
were available. Some apps were either unavailable for the Darwin
platform or failed to launch. For example, &lt;a href=&quot;https:&#x2F;&#x2F;search.nixos.org&#x2F;packages?channel=unstable&amp;amp;show=sublime4&amp;amp;from=0&amp;amp;size=50&amp;amp;sort=relevance&amp;amp;type=packages&amp;amp;query=sublime&quot;&gt;Sublime Text
Editor&lt;&#x2F;a&gt;,
&lt;a href=&quot;https:&#x2F;&#x2F;search.nixos.org&#x2F;packages?channel=unstable&amp;amp;show=obsidian&amp;amp;from=0&amp;amp;size=50&amp;amp;sort=relevance&amp;amp;type=packages&amp;amp;query=obsidian&quot;&gt;Obsidian&lt;&#x2F;a&gt;,
and &lt;a href=&quot;https:&#x2F;&#x2F;search.nixos.org&#x2F;packages?channel=unstable&amp;amp;show=ledger-live-desktop&amp;amp;from=0&amp;amp;size=50&amp;amp;sort=relevance&amp;amp;type=packages&amp;amp;query=ledger&quot;&gt;Ledger Live
Desktop&lt;&#x2F;a&gt;
are examples of applications that are not accessible for Darwin systems,
as can be seen in each respective package’s “Platforms” list.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;small-frustrations&quot;&gt;Small Frustrations&lt;&#x2F;h3&gt;
&lt;p&gt;A Nix and HM setup can come with its fair share of small
nuisances. I sometimes wish I were the type of person who kept a
meticulous journal with tags and all, as the issues I’ve listed here are
just the few that I can recall from memory.&lt;&#x2F;p&gt;
&lt;p&gt;One of the trade-offs of having Nix manage your configuration files is
that it’s more or less no longer possible to edit them directly in place
(which is a somewhat obvious requirement for such a highly deterministic
build system). Even if you do make edits, they will eventually be
overwritten. If you tweak your Vim configuration file every five
minutes then this will really annoy you.&lt;&#x2F;p&gt;
&lt;p&gt;On MacOS, launcher entries for applications may be missing. For example,
if I install the Alacritty terminal emulator through HM, I
can’t simply use “cmd+space” and type “Alacritty”, to launch it because
MacOS is unaware of its existence. Although HM creates the necessary
files, Finder does not index them. Here’s the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;home-manager&#x2F;issues&#x2F;1341&quot;&gt;GitHub
issue&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I was also missing some man pages at some point, but I think that was
fixable, and I think that &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;home-manager&#x2F;issues&#x2F;432&quot;&gt;this is the now closed GitHub
issue&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Integrating Nix and HM with Fish requires you to find some plugins
first. Initially I used
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lilyball&#x2F;nix-env.fish&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;lilyball&#x2F;nix-env.fish&lt;&#x2F;a&gt;
but later I switched to &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kidonng&#x2F;nix.fish&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;kidonng&#x2F;nix.fish&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;It took a few years until Visual Studio Code in Nix was in a state where
most things just work. It’s still a bit complicated to setup because
there are various options that all have some pros and cons. You can see
the &lt;a href=&quot;https:&#x2F;&#x2F;nixos.wiki&#x2F;wiki&#x2F;Visual_Studio_Code&quot;&gt;documentation here&lt;&#x2F;a&gt;.
Also getting LiveShare to work on MacOS and NixOS requires you to be a
bit mindful about which plugins you need on which platform.&lt;&#x2F;p&gt;
&lt;p&gt;Nix also demands more hard disk space, and the installer needs to create
a new volume. Fortunately, the &lt;a href=&quot;https:&#x2F;&#x2F;determinate.systems&#x2F;posts&#x2F;determinate-nix-installer&quot;&gt;Determinate Nix
Installer&lt;&#x2F;a&gt;
project nowadays provides a straightforward installation process on
MacOS.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;added-complexity-home-manager-abstractions&quot;&gt;Added Complexity &amp;amp; Home Manager Abstractions&lt;&#x2F;h3&gt;
&lt;p&gt;This was the reason I tried to live without Nix and HM for a while!
Nixpkgs is an enormous repository, and the Nix language itself adds to
the complexity. According to &lt;code&gt;tokei&lt;&#x2F;code&gt;, the
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;home-manager&quot;&gt;&lt;code&gt;nix-community&#x2F;home-manager&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
repository has over 50_000 lines of code! It can be a bit unsettling to
think about the sheer number of the layers of technology involved in
“just” installing a few applications and placing files in specific
locations.&lt;&#x2F;p&gt;
&lt;p&gt;Of course, for the most part you don’t care how many lines of code go
into &lt;code&gt;home-manager&lt;&#x2F;code&gt;. Similar to how I have no idea about the size of Vim
and Neovim, yet I rely on them daily.&lt;&#x2F;p&gt;
&lt;p&gt;However, you’ll notice the complexity when something breaks. Fixing
issues in individual packages is usually manageable, but problems
stemming from the underlying infrastructure of Nixpkgs can be daunting.
Nix, being a functional, domain-specific language, is used with a
significant level of abstraction in Nixpkgs. It can be frustratingly
difficult to trace the origin of certain function arguments for example.&lt;&#x2F;p&gt;
&lt;p&gt;I also have some doubts about the level of abstraction in HM.
For instance, the existence of options like
&lt;a href=&quot;https:&#x2F;&#x2F;nix-community.github.io&#x2F;home-manager&#x2F;options.html#opt-programs.neovim.enable&quot;&gt;&lt;code&gt;programs.neovim.enable&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
in both HM and
&lt;a href=&quot;https:&#x2F;&#x2F;search.nixos.org&#x2F;options?channel=unstable&amp;amp;show=programs.neovim.enable&amp;amp;from=0&amp;amp;size=50&amp;amp;sort=relevance&amp;amp;type=packages&amp;amp;query=neovim&quot;&gt;NixOS&lt;&#x2F;a&gt;
is highly confusing. And it’s not just confusing for beginners; I still
find it confusing after 2 years. Are these options equivalent? How can I
spot the differences? Options like &lt;code&gt;programs.alacritty.settings&lt;&#x2F;code&gt; allow
you to write Nix code that gets translated into a &lt;code&gt;.yaml&lt;&#x2F;code&gt; file, which is
neat, I suppose. However, I personally prefer the less sophisticated
approach of directly writing &lt;code&gt;.yaml&lt;&#x2F;code&gt; inline within my Nix script (or
write a separate &lt;code&gt;.yaml&lt;&#x2F;code&gt; file and import it). Otherwise I need to
understand both the upstream configuration and the Nix equivalent of it.
Many packages also have an &lt;code&gt;extraConfig&lt;&#x2F;code&gt; option for adding configuration
that doesn’t have a HM equivalent. This abstraction level
sometimes feels a bit off. I assume it creates a significant maintenance
burden, as upstream configuration options need to be reflected in Home
Manager options. Of course, you can ignore all this and manually create
your configuration files with &lt;code&gt;xdg.configFile&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I’d probably find the level of abstraction of
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;LnL7&#x2F;nix-darwin&quot;&gt;&lt;code&gt;nix-darwin&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; better, but I haven’t
had the time and energy to try it yet.&lt;&#x2F;p&gt;
&lt;p&gt;At the end of the day I really don’t need the per-user installation of
packages and elaborate modules that HM gives me. I’d be perfectly
content with providing a list of packages to install system-wide and a
few basic primitives to generate configuration files in my home folder.
Having said all that, I’m still a happy HM user.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;exploring-life-beyond-nix-home-manager&quot;&gt;Exploring Life Beyond Nix &amp;amp; Home Manager&lt;&#x2F;h2&gt;
&lt;p&gt;I recently decided to give living without Nix and HM a try.
This decision was actually inspired by a brief conversation I had with
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Gabriella439&quot;&gt;Gabriella Gonzalez&lt;&#x2F;a&gt; years ago. I had
noticed her using an incredibly simple setup during some Twitch streams,
so I reached out and asked about it. She kindly provided thoughtful
replies (thank you, Gabriella!) and, at least back then, seemed to be
using a mostly stock macOS setup. That got me thinking… if someone
like her can live without a billion fancy shell integrations and still
be a billion times more productive than me, maybe I could achieve the
same level of competence by emulating her approach?&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#5&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So I reverted to a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cideM&#x2F;dotfiles-simple&quot;&gt;simpler
configuration&lt;&#x2F;a&gt; where I relied
on MacPorts for installing my system-wide tools. I kept Nix around for
running &lt;code&gt;nix develop&lt;&#x2F;code&gt; and accessing the project-specific environments I
mentioned earlier. However, I abandoned the fancy automation.&lt;&#x2F;p&gt;
&lt;p&gt;So, how did it turn out?&lt;&#x2F;p&gt;
&lt;p&gt;Well, typing &lt;code&gt;nix develop ~&#x2F;path&#x2F;to&#x2F;flake#project&lt;&#x2F;code&gt; a thousand times a
day isn’t exactly fun. And I dread the day I install a Neovim plugin
that requires a Rust toolchain. Instead of using a Vim&#x2F;Neovim plugin
manager, I resorted to learning how packages work and ended up becoming
my own package manager with Git submodules. As for tmux and Fish
plugins, I simply stopped using tmux altogether. It’s a bit annoying
because Alacritty lacks splits and tabs. Going without Fish plugins
means living without a Git prompt in my shell, as the bundled Git
prompts are unusable in large repositories like &lt;code&gt;nixpkgs&lt;&#x2F;code&gt;. Without
&lt;code&gt;nix-direnv&lt;&#x2F;code&gt;, I no longer have the convenience of automatic sourcing of
environment variables. Every time I try to replay a database dump on my
local Postgres instance, I’m reminded of this when I encounter the error
message: &lt;code&gt;AWS_S3_REGION is not set.&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Also, it’s quite funny when you run &lt;code&gt;nix-store --gc&lt;&#x2F;code&gt; to reclaim some
space, only to realize that &lt;code&gt;nix-direnv&lt;&#x2F;code&gt; was also preventing your
development environments from being cleaned up (check out this &lt;a href=&quot;https:&#x2F;&#x2F;ianthehenry.com&#x2F;posts&#x2F;how-to-learn-nix&#x2F;saving-your-shell&#x2F;&quot;&gt;this
insightful
post&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;But here’s the thing: Despite its flaws and complexity, I’ve become
incredibly accustomed to the convenience of running &lt;code&gt;nix flake update&lt;&#x2F;code&gt;
and having almost everything on my system updated. I’ve grown accustomed
to typing &lt;code&gt;cd&lt;&#x2F;code&gt; and witnessing my environment magically and instantly
switch.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;determinate.systems&#x2F;posts&#x2F;determinate-nix-installer&quot;&gt;Determinate Systems Nix Installer&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kidonng&#x2F;nix.fish&quot;&gt;&lt;code&gt;kidonng&#x2F;nix.fish&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cideM&#x2F;dotfiles&#x2F;&quot;&gt;My dotfiles&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nix-community.github.io&#x2F;home-manager&#x2F;&quot;&gt;Home Manager&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;ianthehenry.com&#x2F;posts&#x2F;how-to-learn-nix&#x2F;&quot;&gt;Very good blog post series about Nix&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.twitch.tv&#x2F;videos&#x2F;824384307&quot;&gt;Twitch videos by (among others) Gabriella Gonzalez&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;nix-direnv&quot;&gt;Nix direnv&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;nix-direnv#flakes-support&quot;&gt;Nix direnv project shells&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Sometimes you want to install a tool that’s not yet packaged up in
your system package manager of choice. In such cases it can be
tempting to just use something like &lt;code&gt;npm&lt;&#x2F;code&gt; or &lt;code&gt;cargo&lt;&#x2F;code&gt; to install
something globally in your system.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;I really like
&lt;a href=&quot;https:&#x2F;&#x2F;direnv.net&#x2F;man&#x2F;direnv-stdlib.1.html#codepathadd-ltpathgtcode&quot;&gt;&lt;code&gt;PATH_add&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
to automatically add &lt;code&gt;.&#x2F;node_modules&#x2F;.bin&#x2F;&lt;&#x2F;code&gt; to your &lt;code&gt;$PATH&lt;&#x2F;code&gt; whenever
you are in a NodeJS project. That way it’s trivial to use the
project-local formatter and linter, and so on.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;You can manage your developer machine, build applications (kind of
like Bazel), deploy code to remote machines, define those machines,
and more.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;4&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;I’ve ellided some details. You also need to add this input to your Nix Flake, so it can keep track of which version you’ve installed. This is done like this:&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;{
  lspfuzzy.url = &amp;quot;github:ojroques&amp;#x2F;nvim-lspfuzzy&amp;quot;;
  lspfuzzy.flake = false;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;5&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;It didn’t work.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Building a Website With Haskell &amp; Nix</title>
        <published>2021-09-23T00:00:00+00:00</published>
        <updated>2021-09-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://fbrs.io/fp/"/>
        <id>https://fbrs.io/fp/</id>
        
        <content type="html" xml:base="https://fbrs.io/fp/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;I built a website so trivial that you might wonder why I even bother writing
about it. It consists of a static site which is, unfortunately, still built
with Gatsby, a Javascript framework. The content comes from a content
management system called Contentful. The most complex part is the members-only
area, which is the part I rebuilt and what this post is all about.&lt;&#x2F;p&gt;
&lt;p&gt;The members area consists of a handful of routes:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A news feed where administrators can post new messages. It’s plain text with the exception of URLs, which are replaced with proper anchor links. No images.&lt;&#x2F;li&gt;
&lt;li&gt;User management area, where administrators can invite new members or edit and delete existing members. Here you can also filter by user groups and send emails to users you select through checkboxes. That’s the part where I used progressive enhancement. This route also hooks into email sending functionality for messaging someone who was invited to the site.&lt;&#x2F;li&gt;
&lt;li&gt;People can create events, and others can then sign up for these events and also indicate how many guests they bring. Everyone can see who’s coming and who declined, how many guests there are in total. Events can also have attachements, such as PDF files, which are stored on the droplet itself.&lt;&#x2F;li&gt;
&lt;li&gt;People can request a link that let’s them change their password.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The first version was hacked together with Firebase and some serverless functions,
because I didn’t want to maintain a proper backend. The UI was awkwardly fit
into the static site. It worked but it was ugly.&lt;&#x2F;p&gt;
&lt;p&gt;And so one day I decided that it was time for a rewrite! The official reason is
that I considered it too risky to depend on Firebase for everything. Also the
local developer experience was a bit lacking at that time. The honest answer is
that, for quite a long time, I had been looking for a real-world project to
which I could apply all the fancy functional programming (FP) technologies I
picked up over the years. I was holding an FP-shaped hammer and I was just
looking for a suitable nail. This project seemed perfect, since it’s small,
has actual users and even a deadline, but since it’s a project for a family
member there’s no money on the line and I could do whatever I wanted in terms
of tech. And so the idea was born to rewrite the entire website with Haskell,
Nix and PureScript.&lt;&#x2F;p&gt;
&lt;p&gt;In this post I want to share my experiences building this simple backend in
Haskell, Nix and PureScript. You don’t need to know any of these technologies
to follow the blog post. You might not understand every little detail, but I
hope that the overall message is still valuable. I’ll start the post with a
short summary, so you don’t have to read the entire article if you just want
the main conclusions.&lt;&#x2F;p&gt;
&lt;p&gt;Here’s the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cideM&#x2F;lions-backend&quot;&gt;source code&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;haskell&quot;&gt;Haskell&lt;&#x2F;h3&gt;
&lt;p&gt;I’m neutral about using Haskell again in the future.&lt;&#x2F;p&gt;
&lt;p&gt;On the one hand, algebraic data types and an excellent type system make it very
easy to translate my thoughts into code, since branching control flow, based on
a finite number of options, seems to make up the majority of my coding. It’s
kind of liberating to make sweeping changes across the code base, knowing that
the compiler will prevent a lot of mistakes. Haskell also has a surprisingly
large selection of web development frameworks and libraries. I didn’t have to
implement any mission critical functionality myself (encryption, database
communication, routing, and so on).&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, one of the biggest time sinks was mere plumbing. Many
Haskell libraries revolve around specific Monads, created just for that
library. You don’t need to know what Monads are for this blog post, but the
gist is that you often need to write a little bit of glue code, so that
different Monads of different libraries can talk to each other. I’ll write more
about this later. But the end result was I spent way more time on glue code
than I thought. To make things worse, this glue code did not feel like
meaningful progress. It’s a Haskell solution for a Haskell problem after all.&lt;&#x2F;p&gt;
&lt;p&gt;Haskell also has its fair share of historical baggage, which includes, but is
not limited to, an annoying module system, complicated tooling, and a rather
anemic standard library. The last point means you’ll have way too many lines of
code dedicated to imports.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;nix&quot;&gt;Nix&lt;&#x2F;h3&gt;
&lt;p&gt;I would 100% use Nix again to provide a basic developer environment, which
includes compilers, formatters, database libraries, and so on. It is, in my
opinion, best in class in this area and entirely unrivalled. Think &lt;code&gt;nix develop&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Whether or not I’d use it to build the actual project depends on the
programming language and how well supported it is in Nix. Haskell is the Nix
posterchild, Node on the other hand can be hit and miss.&lt;&#x2F;p&gt;
&lt;p&gt;I would not use Nix again to deploy my code. It was fun playing around with
Systemd and SOPS, but the container ecosystem is just too big. Luckily you can
generate Docker containers with nix, which is something I’d like to explore in
the future. Running my NixOS image locally through QEMU was and still is,
frustrating, especially on MacOS. Additionally, my GitHub action workflow that
builds the application, runs end-to-end tests and deploys it, takes 25 minutes.
For a website of this size that is insane.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sqlite&quot;&gt;SQLite&lt;&#x2F;h3&gt;
&lt;p&gt;I love SQLite. It has quirks and historical baggage but at the end of the day
it’s a robust, battle tested and simple tool that I find to be a joy to use.
You can easily spin up an in-memory database for unit tests, it comes with a
surprising number of features, such as JSON tooling, and it’s just a file at
the end of day. This kind of simplicity is refreshing. Also shoutout to
&lt;a href=&quot;https:&#x2F;&#x2F;litestream.io&#x2F;&quot;&gt;Litestream&lt;&#x2F;a&gt; for database backups.&lt;&#x2F;p&gt;
&lt;p&gt;10&#x2F;10 would use again.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;purescript&quot;&gt;PureScript&lt;&#x2F;h3&gt;
&lt;p&gt;I’ve written 140 lines of PureScript (PS) code in this project, which is
nothing. It’s used for progressive enhancement of markup rendered on the
server, which means inserting DOM elements and interactivity into existing DOM
nodes. Unfortunately I couldn’t find any good PS libraries for this, so I had
to resort to writing very verbose and tedious code that looks like a one-to-one
translation from Javascript. All of the PS web frameworks and libraries I saw
want to own the markup they render, like React. So instead of surgically
injecting interactivity into existing DOM elements, you hand control over an
entire subtree of the DOM to PS. But that would have meant duplicating the
rendering (first render with Haskell on the server then with PS on the client)
of some routes in PS, which seemed like too much work.&lt;&#x2F;p&gt;
&lt;p&gt;For this project PS was not a good choice, as it meant additional complexity
and an unnecessarily large bundle for little to no gain. I like the language
though. As such I just can’t say if I would use PS again in the future based on
this project alone.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;deep-dive&quot;&gt;Deep Dive&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;haskell-1&quot;&gt;Haskell&lt;&#x2F;h3&gt;
&lt;p&gt;Haskell the language is really not complicated. But the ecosystem can be. I
frequently found myself spending too much time solving problems that only exist
in Haskell. These problems are usually the result of having to combine custom
Monads (which you can think of as small, domain specific languages) from
different libraries, something I alluded to already in the summary. For
example, I struggled &lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;haskell&#x2F;comments&#x2F;jyzc3w&#x2F;how_to_avoid_infinite_type_when_lifting&#x2F;&quot;&gt;quite a
bit&lt;&#x2F;a&gt;
with logging, which has only ever happened once before, in Clojure, where
logging is &lt;a href=&quot;https:&#x2F;&#x2F;lambdaisland.com&#x2F;blog&#x2F;2020-06-12-logging-in-clojure-making-sense-of-the-mess&quot;&gt;the final
frontier&lt;&#x2F;a&gt;.
But let me explain in a bit more detail why logging can be surprisingly tricky.&lt;&#x2F;p&gt;
&lt;p&gt;Here’s a snippet from the README of
&lt;a href=&quot;https:&#x2F;&#x2F;hackage.haskell.org&#x2F;package&#x2F;scotty&quot;&gt;scotty&lt;&#x2F;a&gt;, a well known web
framework:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;main = scotty 3000 $
  get &amp;quot;&amp;#x2F;:word&amp;quot; $ do
    beam &amp;lt;- param &amp;quot;word&amp;quot;
    html $ mconcat [&amp;quot;&amp;lt;h1&amp;gt;Scotty, &amp;quot;, beam, &amp;quot; me up!&amp;lt;&amp;#x2F;h1&amp;gt;&amp;quot;]
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It doesn’t matter if you know Haskell or not. I’d like to direct your attention
at &lt;code&gt;param &quot;word&quot;&lt;&#x2F;code&gt;, or, applying the function &lt;code&gt;param&lt;&#x2F;code&gt; to the string &lt;code&gt;&quot;word&quot;&lt;&#x2F;code&gt;.
Maybe you can guess that this extracts the value of the route parameter we
defined in the preceding line, with &lt;code&gt;&quot;&#x2F;:word&quot;&lt;&#x2F;code&gt;. But isn’t it weird that we’re
not passing the HTTP request to the &lt;code&gt;param&lt;&#x2F;code&gt; function? Where does it get
the &lt;em&gt;request&lt;&#x2F;em&gt; paramter from, then? The answer is too complicated for this blog
post, but suffice it to say that there’s some magic going on behind the scenes.
And this magic is made possible by the Scotty Monad.&lt;&#x2F;p&gt;
&lt;p&gt;Now, what if you want to also do some logging in your HTTP handlers? There’s a
really nice library called
&lt;a href=&quot;https:&#x2F;&#x2F;hackage.haskell.org&#x2F;package&#x2F;katip-0.8.5.0&quot;&gt;katip&lt;&#x2F;a&gt;, and it also has
this very neat but also weird looking code:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;main :: IO ()
main = do
  -- ellided for brevity
  katipAddNamespace &amp;quot;additional_namespace&amp;quot; $ katipAddContext (sl &amp;quot;some_context&amp;quot; True) $ do
    $(logTM) WarningS &amp;quot;Now we&amp;#x27;re getting fancy&amp;quot;
  katipNoLogging $ do
    $(logTM) DebugS &amp;quot;You will never see this!&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;katipAddNamespace&lt;&#x2F;code&gt; function does the same thing as any other structured,
hierarchical logging framework. Any log expressions in the indentend block of
code on the following lines will have this new namespace added to them. This
way the caller can add some additional context to the logger and the callee
doesn’t need to know or care about these things. As a proponent of structured,
hierarchical logging, I find this super neat. But, unlike in Go, where you’d do
something like&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go &quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;newLogger := oldLogger.With(&amp;quot;key&amp;quot;, &amp;quot;value&amp;quot;)
newLogger.Info(&amp;quot;whatever&amp;quot;)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;the &lt;code&gt;newLogger&lt;&#x2F;code&gt; variable is nowhere to be seen. You might at first glance think
that we’re passing an anonymous function to &lt;code&gt;katipAddNamespace&lt;&#x2F;code&gt; (the &lt;code&gt;$ do&lt;&#x2F;code&gt;
part maybe?), but even if that were the case, we’re clearly not accepting any
arguments in that anonymous function. So what happens to the modified logger?
Well, the answer is, it’s complicated. Just like with Scotty, there’s a custom Monad
that takes care of all this plumbing for us behind the scenes.&lt;&#x2F;p&gt;
&lt;p&gt;Of course the logger and its contexts and namespaces need to live somewhere. In
a typical setup you create a record that holds your application environment.
And in that environment you store the logger. You then need to teach Katip how
it can access and modify the logger in that environment. It’s essentially like
implementing an interface for a struct, if you’re a Go person.&lt;&#x2F;p&gt;
&lt;p&gt;But then you also need to teach Scotty about this custom Monad. Instead of
working with
&lt;a href=&quot;https:&#x2F;&#x2F;hackage.haskell.org&#x2F;package&#x2F;scotty-0.12&#x2F;docs&#x2F;Web-Scotty.html&quot;&gt;&lt;code&gt;Web.Scotty&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
you import
&lt;a href=&quot;https:&#x2F;&#x2F;hackage.haskell.org&#x2F;package&#x2F;scotty-0.12&#x2F;docs&#x2F;Web-Scotty-Trans.html&quot;&gt;&lt;code&gt;Web.Scotty.Trans&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;,
which states in its opening paragraph:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The functions in this module allow an arbitrary monad to be embedded in
Scotty’s monad transformer stack in order that Scotty be combined with other
DSLs.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Which is exactly what I wanted to do. And at this point the whole house of
cards may or may not fall apart. Because custom Monads often come with
constraints. As in, if you want to run this custom Monad you need to make sure
that the context in which it runs supplies X, Y and Z. And then you start
wondering how those constraints will fit into the bigger picture of all the
other custom Monads you need to satisfy. For Scotty and Katip this ended up
being not too
&lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;haskell&#x2F;comments&#x2F;jyzc3w&#x2F;how_to_avoid_infinite_type_when_lifting&#x2F;&quot;&gt;crazy&lt;&#x2F;a&gt;,
but for another library – &lt;code&gt;co-log&lt;&#x2F;code&gt; – I was unable to achieve my goal at all.
If this whole paragraph sounds a bit hand-wavy, please check out &lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;haskell&#x2F;comments&#x2F;krke1o&#x2F;how_to_create_colog_instance_for_scotty&#x2F;&quot;&gt;this Reddit
question&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;65599741&#x2F;how-to-make-co-logs-withlog-work-with-scotty&quot;&gt;and this StackOverflow
(SO)&lt;&#x2F;a&gt;
post.&lt;&#x2F;p&gt;
&lt;p&gt;So yes, Haskell can be concise, expressive and type safe. But getting there can
be a pain, at least in the beginning. I do believe that over time this stops
being a problem, as you get more and more familiar with the Haskell type system
and the ecosystem.&lt;&#x2F;p&gt;
&lt;p&gt;Aside from Monads, there was at least one other recurring topic that made me
scratch my head, and that’s how to deal with control flow and early return.&lt;&#x2F;p&gt;
&lt;p&gt;Here’s what 90% of my Go code looks like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go &quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;someValue, err := someFunc()
if err != nil {
  return errors.WithMessagef(err, &amp;quot;something went wrong with thing %s&amp;quot;, id)
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Countless people have complained about the repetitiveness and boilerplate, but
I actually don’t mind it at all. The pattern is always the same, so it’s very
easy for me to follow the control flow inside a function. Additionally, it’s
trivial to return as early as possible. In fact, returning early is something
most people probably don’t even give a second thought to, since it’s just so
easy in imperative languages with statements.&lt;&#x2F;p&gt;
&lt;p&gt;What does the above look like in Haskell then?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;case someFunc of
  Left err -&amp;gt; Left ([i|something went wrong with thing #{s}: #{err}|])
  Right -&amp;gt; -- keep going
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I suspect that many seasoned Haskellers will take fault with the above snippet
though, because it’s needlessly verbose. And I kind of agree, and I’ve spent
way too much time converting to and from various control flow patterns in this
project. とにかく, anyway, what’s going on here? &lt;code&gt;someFunc&lt;&#x2F;code&gt; doesn’t return a
normal value and an error, it also doesn’t throw exceptions, rather it returns
a &lt;code&gt;Result&lt;&#x2F;code&gt; type (called &lt;code&gt;Either&lt;&#x2F;code&gt;). We then pattern match on the two possible
variations of this result type. &lt;code&gt;Left&lt;&#x2F;code&gt; if there’s an error, &lt;code&gt;Right&lt;&#x2F;code&gt; if
everything’s fine. Think &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;result&#x2F;&quot;&gt;Rust’s result&lt;&#x2F;a&gt;
type.&lt;&#x2F;p&gt;
&lt;p&gt;But what if you have several function calls that all return different kinds of
results? Consider the following scenario:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Unmarshal query parameters&lt;&#x2F;li&gt;
&lt;li&gt;Check if user is authorized&lt;&#x2F;li&gt;
&lt;li&gt;Get entity from database&lt;&#x2F;li&gt;
&lt;li&gt;Perform some business logic with user and database entity&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Pretty much all of these things can fail in some expected way (meaning
exceptions wouldn’t be appropriate). Here’s a snippet from an older commit that
shows what such code could look like.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;getTokenByValue dbConn token &amp;gt;&amp;gt;= \case
  Nothing -&amp;gt; return $ Left $ TokenNotFound token
  Just tok@Token {..} -&amp;gt; do
    ok &amp;lt;- hasUser dbConn tokenUserId
    if not ok
      then (return . Left $ UserForTokenNotFound tokenUserId)
      else do
        now &amp;lt;- Time.getCurrentTime
        if now &amp;gt;= tokenExpires
          then return $ Left $ TokenExpired tok
          else do undefined -- ...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can see where I’m going with this, right? The increasing indentation level
looks ugly. In all fairness though, this isn’t any more verbose than the
equivalent Go or Typescript code. &lt;strong&gt;I really wish that I had just stuck with
the ugly and verbose version&lt;&#x2F;strong&gt; instead of trying out various different
patterns. I believe that this code is simple, and readable and very easy to
understand. Refactoring this for vanity reasons is not something I’m proud of.&lt;&#x2F;p&gt;
&lt;p&gt;There are &lt;a href=&quot;https:&#x2F;&#x2F;www.haskellforall.com&#x2F;2021&#x2F;05&#x2F;the-trick-to-avoid-deeply-nested-error.html&quot;&gt;some
tricks&lt;&#x2F;a&gt;
for dealing with the ugliness, but in &lt;strong&gt;my personal experience&lt;&#x2F;strong&gt; they often don’t work
in real world scenarios, where more complicated types are involved,
particularly anything with &lt;code&gt;IO&lt;&#x2F;code&gt;. What does work is making liberal use of syntax
sugar, combinators and Monad transformers though.&lt;&#x2F;p&gt;
&lt;p&gt;Here’s a snippet I copied verbatim from my code base, which shows what the
previous code looks like once you throw Monad transformers at the problem:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;token@Token {..} &amp;lt;- Token.get value &amp;gt;&amp;gt;= E.note&amp;#x27; (NotFound value)
ok &amp;lt;- User.exists tokenUserId
E.unless ok $ E.throwError (NoUser tokenUserId)
now &amp;lt;- liftIO $ Time.getCurrentTime
E.when (now &amp;gt;= tokenExpires) (E.throwError $ Expired token)
return $ Valid token
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is probably illegible to folks who are not familiar with Haskell, so here’s a hopefully human readable translation.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;text&quot; class=&quot;language-text &quot;&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Get some value and abort with a NotFound error if it&amp;#x27;s not there
Unless the user exists, abort with a NoUser error
Get the current time
When the current time is greater than the token expiration, abort
Return a valid token
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This version of the Haskell snippet doesn’t suffer from increasing indentation.
We also return early since behind the scenes Haskell still sort of pattern
matches on the various result types and it knows how it can short-circuit the
computation. For example, if &lt;code&gt;ok&lt;&#x2F;code&gt; is false, this will immediately return the
&lt;code&gt;NoUser&lt;&#x2F;code&gt; error, it will not run the remaining lines of that function. There’s
also very little to no Go-style line noise about error checking. I dare say
it’s expressive and concise. But it took me a lot of experimenting to get there
and also required writing &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cideM&#x2F;lions-backend&#x2F;blob&#x2F;770f3e481ee0a7fed27742d0cd8d5f050acfcbfb&#x2F;backend&#x2F;src&#x2F;Error.hs&quot;&gt;some
utility&lt;&#x2F;a&gt;
functions for translating between various custom Monads, again. There are more things I
could complain about here&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, but I hope that my main point here is clear:
translating a simple pattern, early return, to Haskell, without making
the code untolerably ugly, is not straight forward and it can be hard to find
this kind of advice in tutorials and books.&lt;&#x2F;p&gt;
&lt;p&gt;That was a lot of negativity now, so let’s move on to something more positive:
algebraic data types (ADT) and pattern matching. Together, these two features
form the basis for how I model the world in code. Nothing beats the ease with
which this let’s me design branching control flow based on a finite number of
options. I currently write Go for a living and the lack of ADTs has caused more
than one logic bug and runtime panic. Generally, few languages give me the same
confidence as Haskell. It’s really hard to overstate the peace of mind that
comes from not having to worry about nil pointer exceptions and unhandled
cases. While I was writing this blog post I suddenly had an insight and removed
one field from a record that’s used everywhere in my application. In many
languages I would have dreaded this task but in Haskell I simply removed the
field and then followed the compiler errors. At the end I was pretty much 100%
certain that I didn’t break anything.&lt;&#x2F;p&gt;
&lt;p&gt;There are a lot of other things I could write about here, but I think most of
the usual suspects have already been covered in great detail in other blog
posts, on Reddit or on Hackernews. This includes:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Historical baggage like a string type no one really uses&lt;&#x2F;li&gt;
&lt;li&gt;An anemic standard library resulting in lots and lots of imports&lt;&#x2F;li&gt;
&lt;li&gt;No one likes records&lt;&#x2F;li&gt;
&lt;li&gt;Slightly confusing build systems&lt;&#x2F;li&gt;
&lt;li&gt;Modules that are at the same time tedious and not powerful&lt;&#x2F;li&gt;
&lt;li&gt;Lazy evaluation can be tricky for performance and debugging&lt;&#x2F;li&gt;
&lt;li&gt;The typical issues of working with a niche language&lt;&#x2F;li&gt;
&lt;li&gt;…&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;But I don’t find any of these things particularly intersting and they’re also
not deal breakers for me.&lt;&#x2F;p&gt;
&lt;p&gt;I wanted to write about the experience of using Haskell, not the nitty gritty
technical details. So what does it feel like, then? For the most part it’s just
like writing a backend in any other language. Define routes, parse query
parameters, do some authorization and authentication checks, fetch something
from the database, render a document. On a good day, Haskell makes me more
efficient and productive because I spend less time fixing bugs and less time
translating the problem to data structures, because ADTs and the type checker
are just that good. On a bad day, I still find myself deciphering runtime
issues, for example caused by a mismatch between database and Haskell types,
while also spending several evenings just solving Haskell issues.&lt;&#x2F;p&gt;
&lt;p&gt;I’m neutral about using Haskell for future projects, because there are things
about the language I love and others that drive me crazy.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;nix-1&quot;&gt;Nix&lt;&#x2F;h3&gt;
&lt;p&gt;According to &lt;code&gt;tokei&lt;&#x2F;code&gt; this project has 1206 lines of Nix code, which fall into
three categories: developer environment, building parts of the application,
building and deploying the NixOS image that runs on a digital ocean droplet.&lt;&#x2F;p&gt;
&lt;p&gt;I can’t think of a better way to provide all the tools necessary to work with a
project than Nix. Every new project I start uses Nix&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; to provide
instructions for how to create a shell that includes things like compiler,
formatter, database tools, terraform, and so on. In combination with
&lt;a href=&quot;https:&#x2F;&#x2F;fbrs.io&#x2F;fp&#x2F;direnv.net&#x2F;&quot;&gt;direnv.net&lt;&#x2F;a&gt; whenever I &lt;code&gt;cd&lt;&#x2F;code&gt; into such a project my shell
environment is updated automatically. Doing this is as easy as adding the stuff
you need to &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cideM&#x2F;lions-backend&#x2F;blob&#x2F;3aff0eabd91bfd37824a6b814b8dbcdb1edb4c58&#x2F;shell.nix#L44&quot;&gt;a
list&lt;&#x2F;a&gt;,
and it usually just works (and keeps working).&lt;&#x2F;p&gt;
&lt;p&gt;Building the various parts of this application with Nix was also not too much
work, but your mileage here depends on the languages and tools you use in your
project and how well they’re supported in Nix. For Haskell there’s a tool you
can use – &lt;code&gt;cabal2nix&lt;&#x2F;code&gt; – which generates Nix code that contains instructions
for how to build your project, including its Haskell dependencies. You can
mostly just follow the documentation to get something up and running. But
Haskell is an outlier and many other languages don’t enjoy the same level of
support. For some of those languages there are tools that translate lock files
to Nix instructions, but they’re &lt;a href=&quot;https:&#x2F;&#x2F;discourse.nixos.org&#x2F;t&#x2F;status-of-lang2nix-approaches&#x2F;14477&#x2F;20&quot;&gt;not without
issues&lt;&#x2F;a&gt;.
If no such tool exists you’re out of luck and building your application with
Nix will quickly become very, very challenging. Nix limits your ability to make
HTTP requests and interact with the file system. You therefore can’t just take
a command like &lt;code&gt;yarn install&lt;&#x2F;code&gt;, which would download Javascript libraries, and
wrap it in some Nix code. Instead, Nix needs to download each of those
dependencies, and for that it needs at least a URL and a hash to verify the
contents. Good luck quickly whipping up a tool that does that.&lt;&#x2F;p&gt;
&lt;p&gt;In this project I ran into little to no problems in that area though. What I
get in return for building everything with Nix is great caching of build
artefacts, and incredible reproducibility. I can clone the project, run a
single command, and it Just Works™. Additionally, even if it took me a few
hours to figure something out, it was usually a one-time cost.&lt;&#x2F;p&gt;
&lt;p&gt;What did not spark a lot of joy was running my application with Nix, both
locally and remotely. Nix is already a niche technology, but deploying with Nix
is a niche within a niche. Documentation is lackluster and there’s a real
chance that you’ll be the first person to use a bunch of tools in a certain
combination and as such there’s no StackOverflow answer you can just copy from.
Here are some things that tripped me up in no particular order.&lt;&#x2F;p&gt;
&lt;p&gt;You can’t build a NixOS image on a Darwin machine, so you need to run things
through Docker. It’s another layer of indirection and resource usage for no
gain. It’s generally frustrating if you develop on one machine for a while,
only to realize that everything’s broken when you to switch to another OS,
especially in 2021. I wouldn’t go so far as calling Darwin a second class
citizen in Nix, but you’ll have to put in extra effort here and there.&lt;&#x2F;p&gt;
&lt;p&gt;If you run your application inside a NixOS image, how do you actually
(re-)start and monitor the application? I went with Systemd, which was another
piece of technology I needed to learn. Documentation is OK but outside of the
official manpages I found far fewer articles that talked about using Systemd
for backend services than I expected. It therefore took me longer than I wished
to figure out how to pass credentials to my application, share a database
directory between different Systemd services, which syntax goes where, and so
on. If I wanted to debug things on MacOS I needed to build the image through
Docker and then I also ended up running a QEMU VM through Docker. You’re
really on your own for a lot of these tasks and at some point I was tired of
figuring out one thing only be the stuck on the next task.&lt;&#x2F;p&gt;
&lt;p&gt;The biggest time sink is just figuring out what arguments a Nix function takes,
which arguments are magically and silently passed through but can be customized
(and how), and what the function returns. My secret weapon here is GitHub code
search. Nothing beats seeing working code. I rarely benefit from reading the
official manual, since it doesn’t contain enough runnable examples. I do spend
a lot of time in issues, PRs and in source code.&lt;&#x2F;p&gt;
&lt;p&gt;Consider Nix a slider that goes from local environment all the way to
production environment. The further right you go, the less likely it is that
you can just follow a cookbook. It’s therefore not a big surprise that I would:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Always use Nix for local development&lt;&#x2F;li&gt;
&lt;li&gt;Sometimes use it for building the application&lt;&#x2F;li&gt;
&lt;li&gt;Probably not use it again for deployment&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;purescript-1&quot;&gt;PureScript&lt;&#x2F;h3&gt;
&lt;p&gt;This project was originally meant to be a super simple, single Haskell file
that implements a server that does not require any client side code. I really missed that mark.&lt;&#x2F;p&gt;
&lt;p&gt;I added PureScript (PS) because there’s no HTML-only way of toggling a bunch of
checkboxes at once. The use case is to select a few (or all) users from a list
and then click a button to send an email with all selected users added as
recipients.&lt;&#x2F;p&gt;
&lt;p&gt;The idea was to progressively enhance the server-side markup. On page load,
reveal the hidden “send email” button and inject a checkbox into every cell of
the users table. Do not replace the entire users table with markup rendered on
the client, because that would have meant reimplementing all of the markup in
PS. Or figuring out a way of sharing my Haskell template code with PS, but that
sounded like a lot of work. Unfortunately PS doesn’t seem to have any
libraries that help with that kind of task. Most of its ecosystem seems to
revolve around React-like libraries that want full control over a DOM node.&lt;&#x2F;p&gt;
&lt;p&gt;So I ended up translating Javascript to PS almost word by word and as such the code looks like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;purescript&quot; class=&quot;language-purescript &quot;&gt;&lt;code class=&quot;language-purescript&quot; data-lang=&quot;purescript&quot;&gt;getCheckboxState :: Node -&amp;gt; Effect { email :: String, checked :: Boolean }
getCheckboxState checkbox = do
  checkboxAsEl &amp;lt;- maybe (throw &amp;quot;couldn&amp;#x27;t convert checkbox to element&amp;quot;) pure $ Element.fromNode checkbox
  checkbox&amp;#x27; &amp;lt;- maybe (throw &amp;quot;couldn&amp;#x27;t convert checkbox to input element&amp;quot;) pure $ InputElement.fromNode checkbox
  isChecked &amp;lt;- InputElement.checked checkbox&amp;#x27;
  email &amp;lt;- Element.getAttribute &amp;quot;data-email&amp;quot; checkboxAsEl &amp;gt;&amp;gt;= maybe (throw &amp;quot;no data-email attr&amp;quot;) pure
  pure { email: email, checked: isChecked }
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is the same as chaining &lt;code&gt;document.querySelector&lt;&#x2F;code&gt; and getting and setting
DOM node attributes. Except that in PS I had to cast from one node type to
another a lot. It’s a bit puzzling and I’m still not sure if I overlooked
something really obvious, but take a look at
&lt;a href=&quot;https:&#x2F;&#x2F;pursuit.purescript.org&#x2F;packages&#x2F;purescript-web-dom&#x2F;5.0.0&#x2F;docs&#x2F;Web.DOM.Element&quot;&gt;&lt;code&gt;Web.DOM.Element&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
and see for yourself. I think you’re not meant to write “low-level” code like
that. It’s probably better to wrap it in more expressive, high-level APIs.
Since I couldn’t find any of those in the form of ready-to-use libraries, and
didn’t want to abstract something I only did once, ugly code it is.&lt;&#x2F;p&gt;
&lt;p&gt;I was pleasently surprised by the Nix support though, which seems to mostly be
the work of a single person,
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;justinwoo&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;justinwoo&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I wish I could say more about PS, because it’s actually a nice language, but it
just wasn’t a good fit for this project. I think the client side code is in the
kilobytes, whereas a vanilla JS implementation would have been much, much
leaner.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Haskell is still my favorite programming language. Rust sounds like a modern
and more refined take on the concept of pair programming with a very capable
compiler, but whenever I tried it I quickly missed the ease of writing code in
a high level language. But as much as I enjoy using Haskell, I can’t ignore the
frustration it has caused me, and how much slower it often makes me during the
initial implementation of something.&lt;&#x2F;p&gt;
&lt;p&gt;I still believe that Haskell, with a good enough understanding of its more
advanced language extensions, can be an incredibly productive language. The
more potential bugs you can rule out through the type system, the less
maintenance down the road. But getting there takes a long time.&lt;&#x2F;p&gt;
&lt;p&gt;My goal for the next 12 months is to do another project of roughly the same
complexity level, but use tools that value simplicity above everything else.&lt;&#x2F;p&gt;
&lt;p&gt;For example, instead of devising a complicated secret management solution, that
could end up being risky because you don’t understand how it works, I could
also just &lt;code&gt;ssh&lt;&#x2F;code&gt; into the server and create a file with the secrets and call it
a day. Instead of using Nix to manage the complexity of a sprawling dependency
tree, what if my app barely had any dependencies?&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;For example, I would strongly recommend to immediately catch potential
exceptions thrown by a function that has &lt;code&gt;MonadThrow&lt;&#x2F;code&gt; (if I recall
correctly), because I’ve had surprising errors when the exception type was
not what I thought, because somewhere a function happened to have a
&lt;code&gt;MonadThrow&lt;&#x2F;code&gt; in its signature but with the exception type hardcoded to
string. I’ve also created subtle bugs in code where I thought I was
short-circuiting but I was actually just returning &lt;code&gt;IO Left&lt;&#x2F;code&gt; instead of
&lt;code&gt;Left&lt;&#x2F;code&gt;. So this &lt;code&gt;mtl&lt;&#x2F;code&gt;-style control flow is not without its pitfalls.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;More specifically a Nix Flake&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Ramda vs. Vanilla Javascript</title>
        <published>2021-03-09T00:00:00+00:00</published>
        <updated>2021-03-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://fbrs.io/ramda/"/>
        <id>https://fbrs.io/ramda/</id>
        
        <content type="html" xml:base="https://fbrs.io/ramda/">&lt;p&gt;I’m a fan of functional programming (FP), especially when it’s coupled with a powerful type system as in Haskell. But my day job revolves around Go and Javascript and involves fairly little FP. Unfortuntately the only person I can blame for that is myself! Apparently I’m not doing enough internal lobbying to convince people of the merits of FP.&lt;&#x2F;p&gt;
&lt;p&gt;If I’m honest, the reason I haven’t really pushed for FP is because I’m not convinced that it is indeed the better, default choice for teams that don’t have much FP expertise to begin with. Before I can convince anyone else, I’ll have to convince myself. Therefore I will start gathering examples of real life code that I can analyze through both the FP and the imperative lens. Hopefully over time I’ll come to a personal conclusion and it’ll have the nice side effect of giving me plenty of arguments for future discussions.&lt;&#x2F;p&gt;
&lt;p&gt;Today’s example is a run of the mill data transformation. I need to transform a flat list of objects into nested objects, which will then be passed to the view layer, where each component will peel off one layer. In other words, I’m denormalizing data for maximum ease in the view layer. The snippets and code will include some place holders here and there and I won’t be mentioning the actual view layer and logic. The only thing that’s relevant here is getting the data from shape A to shape B.&lt;&#x2F;p&gt;
&lt;p&gt;In the actual code the &lt;code&gt;heading&lt;&#x2F;code&gt; is derived from &lt;code&gt;first_name&lt;&#x2F;code&gt; and &lt;code&gt;last_name&lt;&#x2F;code&gt; but in the benchmarks and examples I replaced it with a placeholder, since it’s irrelevant to this post.&lt;&#x2F;p&gt;
&lt;p&gt;The code, including benchmarks, can be found on &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cideM&#x2F;ramda-vanilla-benchmark&quot;&gt;GitHub&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript &quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;const input = [
  {
    section: &amp;quot;barsection&amp;quot;,
    author: { first_name: &amp;quot;foo&amp;quot;, last_name: &amp;quot;bar&amp;quot;, id: &amp;quot;123&amp;quot; },
    content: &amp;quot;foo note&amp;quot;,
  },
  {
    section: &amp;quot;barsection&amp;quot;,
    author: { first_name: &amp;quot;bax&amp;quot;, last_name: &amp;quot;bar&amp;quot;, id: &amp;quot;111&amp;quot; },
    content: &amp;quot;bax note&amp;quot;,
  },
  {
    section: &amp;quot;foosection&amp;quot;,
    author: { first_name: &amp;quot;bert&amp;quot;, last_name: &amp;quot;bar&amp;quot;, id: &amp;quot;223&amp;quot; },
    content: &amp;quot;bert note&amp;quot;,
  },
  {
    section: &amp;quot;foosection&amp;quot;,
    author: { first_name: &amp;quot;bert&amp;quot;, last_name: &amp;quot;bar&amp;quot;, id: &amp;quot;223&amp;quot; },
    content: &amp;quot;another bert note&amp;quot;,
  },
];

const output = {
  barsection: {
    len: 2,
    data: [
      { id: &amp;quot;111&amp;quot;, heading: &amp;quot;bax&amp;#x27;&amp;quot;, contents: [&amp;quot;bax note&amp;quot;] },
      {
        id: &amp;quot;123&amp;quot;,
        heading: &amp;quot;foos&amp;quot;,
        contents: [&amp;quot;foo note&amp;quot;],
      },
    ],
  },
  foosection: {
    len: 2,
    data: [
      {
        id: &amp;quot;223&amp;quot;,
        heading: &amp;quot;berts&amp;quot;,
        contents: [&amp;quot;bert note&amp;quot;, &amp;quot;another bert note&amp;quot;],
      },
    ],
  },
};
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you focus on the output you’ll notice that we’re doing two aggregations here. We group the input by its section key and we also group all entries by the same author per section. The resulting &lt;code&gt;data&lt;&#x2F;code&gt; value is an array so that the view layer can iterate over it without having to first call &lt;code&gt;Object.values&lt;&#x2F;code&gt; on it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;vanilla&quot;&gt;Vanilla&lt;&#x2F;h2&gt;
&lt;p&gt;The vanilla solution is imperative to a fault. Personally I can’t glance at the code and immediately get an idea of what it’s doing on a high level. There’s too much plumbing going on, especially the checks and initializations to make sure we’re not accessing a key on an undefined object. Others will consider this an advantage though, because there’s absolutely no magic. Also note that the snippet doesn’t include any imports because there are none! One thing I like about it is that object initialization makes the shape of the data clearer. Additionally, it’s easy to see the execution model (e.g., number of iterations). Zero magic.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript &quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;const vanillaFn = (notes) =&amp;gt; {
  const grouped = {};

  notes.forEach((note) =&amp;gt; {
    const {
      author: { id: currentId },
      content,
      section,
    } = note;

    if (!grouped[section]) grouped[section] = { len: 0, data: {} };

    grouped[section].len += 1;

    if (!grouped[section].data[currentId])
      grouped[section].data[currentId] = {
        contents: [],
        heading: &amp;quot;&amp;quot;,
        id: &amp;quot;&amp;quot;,
      };

    const userNotes = grouped[section].data[currentId];
    userNotes.heading = &amp;quot;placeholder&amp;quot;;
    userNotes.contents.push(content);
    userNotes.id = currentId;
  });

  Object.keys(grouped).forEach((sectionId) =&amp;gt; {
    grouped[sectionId].data = Object.values(grouped[sectionId].data);
  });

  return grouped;
};
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;ramda&quot;&gt;Ramda&lt;&#x2F;h2&gt;
&lt;p&gt;If you want to write functional JS in any significant capacity you’ll need a third party library. For many people &lt;code&gt;lodash&#x2F;fp&lt;&#x2F;code&gt; will be the first choice since &lt;code&gt;lodash&lt;&#x2F;code&gt; (without the fp part) is probably already in use anyway.&lt;&#x2F;p&gt;
&lt;p&gt;I would really encourage you to look into Ramda though, since it includes many functions that are simply missing from Lodash but which I’d consider an important part of the FP toolset and mindset. With Lodash you won’t get to experience the full power and conciseness of FP.&lt;&#x2F;p&gt;
&lt;p&gt;Ramda’s rich API made me write two different versions of the code in question. I can’t help but notice that it’s quite typical for me to spend more time thinking about how to solve something when I’m using FP. Contrast this with Go where iterating means &lt;code&gt;range&lt;&#x2F;code&gt; and that’s it. With FP you might spend the next hour musing about the pros and cons of various list comprehension and traversal interfaces.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;version-a&quot;&gt;Version A&lt;&#x2F;h3&gt;
&lt;p&gt;The first version makes heavy use of lenses to assign data at various levels of nesting. Other than that it’s essentially just a fold (&lt;code&gt;reduce&lt;&#x2F;code&gt; in JS). The second operation just converts objects into arrays at the &lt;code&gt;data&lt;&#x2F;code&gt; key (see the second code snippet below). I’d consider this version quite close to the vanilla implementation, since both operations in the call to &lt;code&gt;pipe&lt;&#x2F;code&gt; map to a block of code in the vanilla implementation.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript &quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;const lensProp = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;lensProp&amp;quot;);
const compose = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;compose&amp;quot;);
const values = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;values&amp;quot;);
const reduce = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;reduce&amp;quot;);
const map = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;map&amp;quot;);
const defaultTo = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;defaultTo&amp;quot;);
const lensPath = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;lensPath&amp;quot;);
const set = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;set&amp;quot;);
const concat = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;concat&amp;quot;);
const inc = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;inc&amp;quot;);
const over = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;over&amp;quot;);
const pipe = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;pipe&amp;quot;);

const safeIncrement = pipe(defaultTo(0), inc);
const safeConcat = (xs) =&amp;gt; pipe(defaultTo([]), concat([xs]));

const reducer = (object, { author: { id: currentId }, content, section }) =&amp;gt; {
  const lenL = lensPath([section, &amp;quot;len&amp;quot;]);
  const userL = lensPath([section, &amp;quot;data&amp;quot;, currentId]);
  const idL = compose(userL, lensProp(&amp;quot;id&amp;quot;));
  const contentsL = compose(userL, lensProp(&amp;quot;contents&amp;quot;));
  const headingL = compose(userL, lensProp(&amp;quot;heading&amp;quot;));

  return pipe(
    over(lenL, safeIncrement),
    set(idL, currentId),
    over(contentsL, safeConcat(content)),
    set(headingL, &amp;quot;placeholder&amp;quot;),
  )(object);
};

const ramdaFn = pipe(reduce(reducer, {}), map(over(lensProp(&amp;quot;data&amp;quot;), values)));
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript &quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;const a = {
  dynamicKeyA: {
    dynamicKeyB: { foo: 1 },
    dynamicKeyC: { foo: 2 },
  },
};

const b = {
  dynamicKeyA: [{ foo: 1 }, { foo: 2 }],
};
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;version-b&quot;&gt;Version B&lt;&#x2F;h3&gt;
&lt;p&gt;This version is quite different from the other two, and I’m finding it hard to correlate the individual operations to code in the vanilla implementation. The second part, replacing an object with an array of its values, is still the same. But the first part further differentiates between transforming a single input value and combining those transformed values. It doesn’t use lenses at all, and instead introduces the concept of transducers (hello Clojure!). In my opinion this is the cleanest looking version, because it elegantly skirts the issue of having to deal with operations on potentially uninstantiated, nested objects.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript &quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;const mergeDeepWithKey = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;mergeDeepWithKey&amp;quot;);
const pipe = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;pipe&amp;quot;);
const concat = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;concat&amp;quot;);
const transduce = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;transduce&amp;quot;);
const map = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;map&amp;quot;);
const over = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;over&amp;quot;);
const lensProp = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;lensProp&amp;quot;);
const values = require(&amp;quot;ramda&amp;#x2F;src&amp;#x2F;values&amp;quot;);

const mapper = ({ author: { id: currentId }, content, section }) =&amp;gt; ({
  [section]: {
    len: 1,
    data: {
      [currentId]: {
        heading: &amp;quot;placeholder&amp;quot;,
        contents: [content],
        id: currentId,
      },
    },
  },
});

const merger = (key, left, right) =&amp;gt; {
  switch (key) {
    case &amp;quot;len&amp;quot;:
      return left + right;
    case &amp;quot;heading&amp;quot;:
      return left;
    case &amp;quot;id&amp;quot;:
      return left;
    case &amp;quot;contents&amp;quot;:
      return concat(left, right);
  }
};

const ramdaFn = pipe(
  transduce(map(mapper), mergeDeepWithKey(merger), {}),
  map(over(lensProp(&amp;quot;data&amp;quot;), values)),
);
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;discussion&quot;&gt;Discussion&lt;&#x2F;h2&gt;
&lt;p&gt;We’ve looked at what the code is doing and how it’s doing that in three different ways. Now it’s time to wade into dangerous territory and attempt to compare FP and imperative programming in this tiny piece of code.&lt;&#x2F;p&gt;
&lt;p&gt;I’ll analyze each snippet based on the following metrics:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Performance&lt;&#x2F;li&gt;
&lt;li&gt;Lines of Code &amp;amp; Dependencies&lt;&#x2F;li&gt;
&lt;li&gt;Readability&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If you think that I’m overlooking a really important metric please let me know at &lt;code&gt;yuuki at protonmail dot com&lt;&#x2F;code&gt; or on whatever website I publish this post. Lastly, I’m not an academic. I’m sorry if the discussion of the individual metrics lacks rigor. Again, do let me know!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;performance&quot;&gt;Performance&lt;&#x2F;h3&gt;
&lt;p&gt;This one we can measure! The repository I linked at the start of this post includes not just the different snippets but also a benchmark. The benchmark consists of a list of 3 input objects for two sections and two authors, which I repeat &lt;code&gt;n&lt;&#x2F;code&gt; number of times. The resulting list of lists is flattened and then used as input to each code snippet. The test data isn’t very refined but it should be good enough for a relative performance comparison.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;text&quot; class=&quot;language-text &quot;&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;n = 30
ramda x 1,067 ops&amp;#x2F;sec ±6.83% (69 runs sampled)
ramda merge deep x 6,301 ops&amp;#x2F;sec ±4.96% (77 runs sampled)
vanilla x 223,259 ops&amp;#x2F;sec ±5.09% (76 runs sampled)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With an input list of length 30 the vanilla version is about 35 times faster
than the FP versions. Increasing it to 15000 makes the difference even more
drastic, with vanilla JS now 100 times faster. The difference between the two
FP versions is negligible.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;text&quot; class=&quot;language-text &quot;&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;n = 15000
ramda x 2.19 ops&amp;#x2F;sec ±9.46% (10 runs sampled)
ramda merge deep x 7.70 ops&amp;#x2F;sec ±6.06% (24 runs sampled)
vanilla x 777 ops&amp;#x2F;sec ±3.42% (82 runs sampled)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I also did a &lt;em&gt;very basic&lt;&#x2F;em&gt; memory consumption test, by just commenting out some of the benchmark code and running the functions directly with &lt;code&gt;$ command time -f &#x27;%M&#x27; node index.js&lt;&#x2F;code&gt;. Results:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;text&quot; class=&quot;language-text &quot;&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;ramda            79756KB
ramda merge deep 79156KB
vanilla          32096KB
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Don’t take these values literally, they’re only useful for comparison purposes. Just like with speed, vanilla clearly comes out ahead.&lt;&#x2F;p&gt;
&lt;p&gt;So what do we make of these results? I was expecting Ramda to be slow. I’d also suspect that if you can replicate some of the FP examples with &lt;code&gt;lodash&#x2F;fp&lt;&#x2F;code&gt; you’ll see a speed up. I’ve glanced at Ramda’s source and it implements the FP concepts with much more rigor than Lodash. As an end user you don’t care about that, but then again Lodash is missing a lot of important FP functions from its API.&lt;&#x2F;p&gt;
&lt;p&gt;Personally performance is not my primary worry when writing client side Javascript. Clients shouldn’t have to deal with tens of thousands of objects. On the other hand Ramda is &lt;strong&gt;a lot&lt;&#x2F;strong&gt; slower. If you’re trying to maintain 60FPS you don’t have lot of wiggle room. I could very well imagine a rich client application that uses large enough lists for Ramda to become a problem.&lt;&#x2F;p&gt;
&lt;p&gt;On the backend side you’re even more likely to work with sufficiently large data. Of course, always keep in mind that any network or file I&#x2F;O might render these micro benchmarks meaningless. If your app is waiting 100ms for a request, it doesn’t matter much if your Ramda code is 5ms slower.&lt;&#x2F;p&gt;
&lt;p&gt;My personal conclusion from this admittedly superficial look at performance is that while it doesn’t rule out Ramda, it means that Ramda will have to be really convincing in all other comparisons.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lines-of-code-dependencies&quot;&gt;Lines of Code &amp;amp; Dependencies&lt;&#x2F;h3&gt;
&lt;p&gt;Why look at size (lines of code)? Users of concise languages will point out that there are studies that have shown that fewer LOC means fewer opportunities for bugs. Based on my own experience I agree with this statement but not without some nuance. One example in favor of reducing LOC is that in Go I constantly write exactly the same code for making a list of things unique, just with different types. At some point I’ll make a dumb mistake that goes unnoticed and lands in production. On the other hand really dense code can be incredibly hard to understand (looking at you Haskell). And lack of understanding is the perfect breeding ground for bugs. In the end I believe that a reasonable reduction in LOC is a good thing, but you shouldn’t become fanatic about it.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;shell&quot; class=&quot;language-shell &quot;&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;$ wc -l vanilla.js ramda.js ramda_merge_deep.js
  31 vanilla.js
  34 ramda.js
  41 ramda_merge_deep.js
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There’s just not enough code to draw a meaningful conclusion here. The primary reason why the vanilla version is the shortest is that it doesn’t require almost a dozen imports. Without those things look a bit different:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;shell&quot; class=&quot;language-shell &quot;&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;$ wc -l vanilla.js ramda.js ramda_merge_deep.js
  31 vanilla.js
  21 ramda.js
  32 ramda_merge_deep.js
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I think it’s safe to assume that across an entire code base Ramda will end up being significantly shorter. You might just eat the added bundle size that comes from importing the entire library instead of individual functions. Even if you keep the imports granular, they don’t add to the complexity of the code and in larger files their impact on LOC will diminish. I don’t have access to a code base that was written in both vanilla JS and Ramda so this will have to remain a reasonable assumption.&lt;&#x2F;p&gt;
&lt;p&gt;Lastly, what is the impact of a library like Ramda on the overall bundle size? Depending on what you use as a point of reference, the &lt;a href=&quot;https:&#x2F;&#x2F;bestofjs.org&#x2F;projects&#x2F;ramda&quot;&gt;12kb&lt;&#x2F;a&gt; that Ramda adds to your bundle size might be completely irrelevant. Many sites ship megabytes of Javascript after all. But if you do care about size then those 12kb will have to pull their weight. Any dependency also adds a bit of maintenance work, although that’s less of an issue with general purpose utility libraries. It’s not like the API for &lt;code&gt;map&lt;&#x2F;code&gt; changes every quarter.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;readability&quot;&gt;Readability&lt;&#x2F;h3&gt;
&lt;p&gt;The final frontier. Few topics evoke such emotional responses as readability. It’s actually kind of funny that readability is often used as both an argument for and against Haskell. My biggest problem is that I don’t even know what I consider readable. I’m a web developer writing CRUD apps, as such ease of getting up to speed and developer velocity are really important for the code I write at work. Personally though I place a higher value on making the high level intent of code as clear as possible. But if you’re a systems developer then clarity of execution might be the most important aspects of readability. By this I mean things like how often does this allocate, when exactly is this future woken up, does this stream in chunks or not at all, and so on. And as I’m writing this I’m not so sure anymore if I’d really favor high level intent over clarity of execution model. Do I want to be known as a developer who wastes resources?&lt;&#x2F;p&gt;
&lt;p&gt;It’s tempting to draw a line between high level and low level coding and define two different sets of readability rules. But about people who do both? Code that needs to be super fast but that’s dealing with really complicated logic?&lt;&#x2F;p&gt;
&lt;p&gt;In an ideal environment I’d focus only on the logic and leave performance to the compiler. But such an environment does not exist. Therefore I will analyze the snippets both with regards to high level intent and clarity of execution model.&lt;&#x2F;p&gt;
&lt;p&gt;The vanilla version makes it quite clear how many iterations will take place. There’s a &lt;code&gt;forEach&lt;&#x2F;code&gt; at the start and another at the end. It also calls two &lt;code&gt;Object&lt;&#x2F;code&gt; methods, which probably do some iterating as well. You’re also not left wondering if there’s any deep cloning going on (there isn’t).&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand it’s not apparent what this code is trying to accomplish. You really need to read it line by line to understand that we’re mostly gathering the &lt;code&gt;content&lt;&#x2F;code&gt; fields of each input value, by section and author.&lt;&#x2F;p&gt;
&lt;p&gt;The first Ramda version is more or less a translation of the imperative code but using lenses. Instead of &lt;code&gt;forEach&lt;&#x2F;code&gt; it’s doing a &lt;code&gt;reduce&lt;&#x2F;code&gt;, but other than that you need to check what each &lt;code&gt;over&lt;&#x2F;code&gt; and &lt;code&gt;set&lt;&#x2F;code&gt; is doing. To make matters worse, I had to create two wrappers so that I can use &lt;code&gt;inc&lt;&#x2F;code&gt; and &lt;code&gt;concat&lt;&#x2F;code&gt; without having to first check for &lt;code&gt;undefined&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I’d argue that this snippet is the worst of the bunch. You lose the clarity of execution model from the vanilla version, without gaining much in terms of high level intent. Developers who are new to FP will be confused by lenses, especially once they see them being composed. Lastly, threading an object through a pipe of &lt;code&gt;set&lt;&#x2F;code&gt; and &lt;code&gt;over&lt;&#x2F;code&gt; will probably look super confusing. We normally don’t think of multiple assignments to object keys as multiple function calls.&lt;&#x2F;p&gt;
&lt;p&gt;So what about Ramda version two? I absolutely love the way I can convert a single input value into a single output value without having to even think about nested objects paths. The shape of the output data is crystal clear as well!&lt;&#x2F;p&gt;
&lt;p&gt;But then you stumble upon &lt;code&gt;mergeDeepWithKey&lt;&#x2F;code&gt; and whatever clarity was gained by the mapping is immediately lost. The switch statement only specifies some keys. You really need to read the documentation to understand what happens with the rest. If you come from an FP background then you’ll probably make the connection between this and implementing semiring for your datastructure. But without that background knowledge it will seem pretty magical, and not in a good way. Additionally, you need to understand how the mapping and merging are used in the &lt;code&gt;transduce&lt;&#x2F;code&gt; call. Clojurists won’t have any issues with that, but the average JS developer is unlikely to be familiar with transducers in general. Also I’ve seen it many times that JS developers are strangely averse to switch statements. I don’t have an explanation for this though.&lt;&#x2F;p&gt;
&lt;p&gt;You could reduce the number of new concepts by separating the whole thing into a &lt;code&gt;map&lt;&#x2F;code&gt; followed by a &lt;code&gt;reduce&lt;&#x2F;code&gt; but then you’re back at square one. You’d need to write code that merges every key in both objects, potentially handling &lt;code&gt;undefined&lt;&#x2F;code&gt; if your &lt;code&gt;reduce&lt;&#x2F;code&gt; starts with an empty object.&lt;&#x2F;p&gt;
&lt;p&gt;For me personally the third snippet is clearly the winner. It’s about as concise as it gets. It shows how to transform a single value. Then it shows how the results will be merged, while omitting keys that use the default merging strategy. But it also requires quite a lot of buy in from a developer who’s not familiar with FP.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Ramda is much more concise, but also significantly slower than vanilla Javascript in this small example. The conciseness comes from using concepts such as lenses, transducers and higher order functions, which most developers are not familiar with. Careless use of functional programming concepts in a language without special support for that is, in my opinion, more likely to lead to unnecessary CPU usage and memory consumption. Of course you can write slow code in any paradigm, but if the most likely thing you’ll do is write a single loop and cram all your functionality in there, you’ll be more likely to experience a “pit of success” moment with regards to performance.&lt;&#x2F;p&gt;
&lt;p&gt;Ultimately, I was hoping to answer the question: would FP be my default paradigm in my next JS project? I don’t know. I think that you’d need to invest a lot of time and energy into mentoring. You’d also need people curious enough to be mentored. I can guarantee you that some of the FP heavy code will come out needlessly complex and abstract in the beginning. This will lead to push back and endless discussions. I’m not sure if that’s really worth it? Maybe it’s better to use a language that was built with FP in mind rather than retrofitting it into JS.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Exploring the Dhall configuration language</title>
        <published>2020-04-28T00:00:00+00:00</published>
        <updated>2020-04-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://fbrs.io/dhall/"/>
        <id>https://fbrs.io/dhall/</id>
        
        <content type="html" xml:base="https://fbrs.io/dhall/">&lt;p&gt;Over the last weekend I looked into the &lt;a href=&quot;https:&#x2F;&#x2F;dhall-lang.org&#x2F;&quot;&gt;Dhall configuration language&lt;&#x2F;a&gt;. I’m a fan of pure, functional programming in general and the works of &lt;a href=&quot;http:&#x2F;&#x2F;www.haskellforall.com&#x2F;&quot;&gt;Gabriel Gonzalez&lt;&#x2F;a&gt; specifically and so Dhall seemed like something I would like. I’m also not super happy with the way we handle kubernetes configuration files at work through helm, so I’m always looking for alternatives to that.&lt;&#x2F;p&gt;
&lt;p&gt;In this post I’ll write down my first impressions of the language, which I got from creating &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cideM&#x2F;dhall-alacritty&quot;&gt;type definitions and default values&lt;&#x2F;a&gt; for the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;alacritty&#x2F;alacritty&quot;&gt;alacritty terminal emulator&lt;&#x2F;a&gt;. In other words: I don’t have a lot of experience with Dhall yet and haven’t used it in a professional context. I’m not going to go through all the language features here, since the website does that much better. Instead, I’ll go over some things which stood out to me while exploring Dhall. After that I’ll show you an example of how Dhall can make working with configs safer &lt;strong&gt;and simpler for the end user&lt;&#x2F;strong&gt; before I get to the closing thoughts. Please also not that this is not an exhaustive introduction to the language. I’ll do my best to add context to all of the code snippets, but not all of them are beginner friendly if you’ve never worked with a pure, functional language before.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;All code snippets in this post use unicode symbols, so &lt;code&gt;forall ()&lt;&#x2F;code&gt; becomes &lt;code&gt;∀ ()&lt;&#x2F;code&gt;. This is &lt;strong&gt;not required&lt;&#x2F;strong&gt; and purely for aesthetical reasons. Additionally, unless noted otherwise, all examples – both inline and code blocks – are runnable and don’t require any additional imports.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;documentation-getting-started&quot;&gt;Documentation &amp;amp; Getting Started&lt;&#x2F;h2&gt;
&lt;p&gt;The first contact with a new language is usually the landing page and the languages’ documentation. In the case of Dhall both are excellent!&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; For a project so young it’s impressive how much documentation exists and how &lt;strong&gt;beginner friendly&lt;&#x2F;strong&gt; it is in general. Especially considering that Dhall has a fair share of overlap with the Haskell community, which is not exactly known for soft documentation. The best resource to get started with Dhall is, in my opinion, the &lt;a href=&quot;https:&#x2F;&#x2F;docs.dhall-lang.org&#x2F;tutorials&#x2F;Language-Tour.html&quot;&gt;language tour&lt;&#x2F;a&gt;, followed by the other tutorials on the page. Additionally, the &lt;a href=&quot;https:&#x2F;&#x2F;discourse.dhall-lang.org&#x2F;&quot;&gt;Discourse&lt;&#x2F;a&gt; forum is active and very helpful.&lt;&#x2F;p&gt;
&lt;p&gt;Dhall makes it super easy to just play around with little snippets of code. You can copy &amp;amp; paste this into your shell &lt;code&gt;echo &#x27;{ key = &quot;Value&quot; }&#x27; | dhall&lt;&#x2F;code&gt; to see what it outputs&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Run it with &lt;code&gt;dhall type&lt;&#x2F;code&gt; or &lt;code&gt;dhall --annotate&lt;&#x2F;code&gt; instead of just &lt;code&gt;dhall&lt;&#x2F;code&gt; to see more information about the expression. In general, exploring the different subcommands and flags of the &lt;code&gt;dhall&lt;&#x2F;code&gt; binary is time well invested. You can also navigate to any file in your project and play around with its contents like so &lt;code&gt;echo &quot;(.&#x2F;file.dhall).someExport&quot; | dhall&lt;&#x2F;code&gt;. And there’s also a &lt;code&gt;dhall repl&lt;&#x2F;code&gt;! I love that kind of interactive development and it makes it super easy to get started with the language.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;union-types&quot;&gt;Union Types&lt;&#x2F;h2&gt;
&lt;p&gt;Having union types for configuration is generally amazing. It’s pretty common that a key only accepts a narrow range of values and union types let you represent those rules pretty much one to one in your code. The compiler will then verify the correctness of your configuration for you. That’s much more relaxed than having to do these checks manually.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; This saves you time and energy since you don’t need to wait for your configuration to be deployed, and rejected, only to discover you made a typo somewhere.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dhall&quot; class=&quot;language-dhall &quot;&gt;&lt;code class=&quot;language-dhall&quot; data-lang=&quot;dhall&quot;&gt;let Action = &amp;lt; Copy | Paste &amp;gt;

let Config = { action : Action }

-- Below doesn&amp;#x27;t compile since DangerousThing is not an allowed value!
-- let myConfig : Config = { action = Action.DangerousThing }

-- This is allowed!
let myConfig : Config = { action = Action.Paste }

in myConfig
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What’s slightly annoying about union types in Dhall is that there’s no way of extending them, or making one union type the subtype of another. Consider the following:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dhall&quot; class=&quot;language-dhall &quot;&gt;&lt;code class=&quot;language-dhall&quot; data-lang=&quot;dhall&quot;&gt;let Type1 = &amp;lt; A | B | C &amp;gt;
let Type2 = &amp;lt; A | B | C | D &amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It’s clear that &lt;code&gt;Type1&lt;&#x2F;code&gt; is “part of” &lt;code&gt;Type2&lt;&#x2F;code&gt;, meaning I should be able to do &lt;code&gt;Type2.A&lt;&#x2F;code&gt; and use that in any function accepting a &lt;code&gt;Type1&lt;&#x2F;code&gt;. But that’s not (yet) a thing in Dhall, even though there’s &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dhall-lang&#x2F;dhall-lang&#x2F;issues&#x2F;175&quot;&gt;an issue for it&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;There are various ways of dealing with this though. In an early version of &lt;code&gt;dhall-alacritty&lt;&#x2F;code&gt;, the base type would be imported into the more extensive types:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dhall&quot; class=&quot;language-dhall &quot;&gt;&lt;code class=&quot;language-dhall&quot; data-lang=&quot;dhall&quot;&gt;let Base = &amp;lt; A | B &amp;gt;

let Extended = &amp;lt; Base : Base | C &amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This works but requires additional work if there are several variations of &lt;code&gt;Extended&lt;&#x2F;code&gt; but you want to implement some shared functionality in the module where &lt;code&gt;Base&lt;&#x2F;code&gt; lives, which has to work on these variations. Imagine a record, which can hold variations of &lt;code&gt;Extended&lt;&#x2F;code&gt;, but the record as a whole mostly consists of shared keys and functionality. The below snippet shows one way of handling this situation in Dhall through the use of polymorphism. The snippet is big but it’s not actually that complicated! It really boils down to &lt;strong&gt;passing your extended union type and a function to handle that extension&lt;&#x2F;strong&gt; to the code implementing the shared functionality. In other words: the shared record and the functions operating on that record know almost everything about said record, except for one key and how to work with it. So you’re supplying them with this last piece of information to make them whole.&lt;&#x2F;p&gt;
&lt;p&gt;The output of the code below is &lt;code&gt;{ extraKey = &quot;C&quot;, sharedKey = &quot;5&quot;, sharedKey2 = &quot;10&quot; }&lt;&#x2F;code&gt; by the way.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;(Also if you’re wondering what &lt;code&gt;merge&lt;&#x2F;code&gt; does, it’s how you pattern match on union types, since there’s no actual pattern matching in the style of Haskell)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dhall&quot; class=&quot;language-dhall &quot;&gt;&lt;code class=&quot;language-dhall&quot; data-lang=&quot;dhall&quot;&gt;let Prelude = https:&amp;#x2F;&amp;#x2F;prelude.dhall-lang.org&amp;#x2F;package.dhall

let Base = &amp;lt; A | B &amp;gt;

let showBase = λ(b : Base) → merge { A = &amp;quot;A&amp;quot;, B = &amp;quot;B&amp;quot; } b

let Extended = &amp;lt; Base : Base | C &amp;gt;

let showExtended =
	  λ(e : Extended)
	  → merge { C = &amp;quot;C&amp;quot;, Base = λ(b : Base) → showBase b } e

let Rec
	: ∀(extraType : Type) → Type
	=   λ(extraType : Type)
	  → { sharedKey : Natural
		, sharedKey2 : Natural
		, extraKey : extraType }

let handleRec
	:   ∀(extraType : Type)
	  → ∀(handleExtraType : extraType → Text)
	  → ∀(rec : Rec extraType)
	  → { sharedKey : Text, sharedKey2 : Text, extraKey : Text }
	=   λ(extraType : Type)
	  → λ(handleExtraType : extraType → Text)
	  → λ(rec : Rec extraType)
	  → { sharedKey = Prelude.Natural.show rec.sharedKey
		, sharedKey2 = Prelude.Natural.show rec.sharedKey2
		, extraKey = handleExtraType rec.extraKey
		}

in  handleRec
	  Extended
	  showExtended
	  { sharedKey = 5, sharedKey2 = 10, extraKey = Extended.C }

&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It’s actually quite amazing that you can do this in your configuration language. Doesn’t mean you have to, of course, and I doubt that it will come up very often.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;polymorphism&quot;&gt;Polymorphism&lt;&#x2F;h2&gt;
&lt;p&gt;The above paragraph brings me to my next point: polymorphism (hope I’m using the word correctly) in Dhall is fairly straight forward. In a type signature, you can use the &lt;code&gt;forall&lt;&#x2F;code&gt; keyword (turned into a pretty unicode symbol by &lt;code&gt;dhall format&lt;&#x2F;code&gt;) to create a type variable and then refer to that variable (and type) in the rest of the signature. Like so (example taken straight from my toy project)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Not a runnable example. I ellided the function body to focus only on the type signature&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dhall&quot; class=&quot;language-dhall &quot;&gt;&lt;code class=&quot;language-dhall&quot; data-lang=&quot;dhall&quot;&gt;let showBindings
	:   ∀(action : Type)
	  → ∀(show : action → Text)
	  → List (KeybindingIn action)
	  → List Keybinding
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Remember that part about extending union types from the paragraph above? That’s exactly what’s going on here. &lt;code&gt;KeybindingIn&lt;&#x2F;code&gt; is used in 3 different contexts and each context needs to first decide which &lt;code&gt;action&lt;&#x2F;code&gt; type to use with &lt;code&gt;KeybindingIn&lt;&#x2F;code&gt; and how that &lt;code&gt;action&lt;&#x2F;code&gt; type can be turned into a string. Armed with that knowledge &lt;code&gt;showBindings&lt;&#x2F;code&gt; can do all the heavy lifting.&lt;&#x2F;p&gt;
&lt;p&gt;This is quite powerful but can also impair readability of course. I dare say that most programmers would probably run away sreaming if you told them that their &lt;em&gt;configuration language&lt;&#x2F;em&gt; requires them to understand snippets like the one above. Especially when their day job is something like Javascript or Go (disclaimer: that’s my day job). In reality you probably won’t need polymorphism in most cases. In the case of the union type you could just copy &amp;amp; paste the common constructors. It’s a bit of a maintenance burden, but I’d rather do that and gain some type safety, than throw out the Dhall baby with the polymorphism bath water. Just because powerful features exist, doesn’t mean you need to use them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;records&quot;&gt;Records&lt;&#x2F;h2&gt;
&lt;p&gt;There are several helper functions and operators, which make working with records really enjoyable and straightforward in Dhall (that’s quite the feat and the same can’t be said about records in Haskell). You can shallow merge two records with the &lt;code&gt;&#x2F;&#x2F;&lt;&#x2F;code&gt; operator. As the word shallow implies, this will completely override nested records:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dhall&quot; class=&quot;language-dhall &quot;&gt;&lt;code class=&quot;language-dhall&quot; data-lang=&quot;dhall&quot;&gt;{ a = { b = 1, c = 2 } } ⫽ { a.b = 1 }
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Returns &lt;code&gt;{ a.b = 1 }&lt;&#x2F;code&gt;, thereby losing the &lt;code&gt;c = 2&lt;&#x2F;code&gt; part. In practice this is less of a danger than it seems, since you’d probably have a type signature making sure that &lt;code&gt;c&lt;&#x2F;code&gt; is always present. There’s also a recursive merge operator, &lt;code&gt;&#x2F;\&lt;&#x2F;code&gt; but it does not allow for collisions. You can merge but you can’t override. So how do you override something that’s nested a few levels deep?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dhall&quot; class=&quot;language-dhall &quot;&gt;&lt;code class=&quot;language-dhall&quot; data-lang=&quot;dhall&quot;&gt;{ a = { b = 1, c = 2 } } with a.c = 3
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;I can’t overstate how amazing this is&lt;&#x2F;strong&gt;. You’d think that a statically typed, pure functional language would be more tedious at working with records than a dynamic language. Also note the use of the &lt;strong&gt;dot operator&lt;&#x2F;strong&gt; here, which is easy to read and write and makes working with nested records much more ergonomic.&lt;&#x2F;p&gt;
&lt;p&gt;Records can also have schemas, which is just a record with two keys, one for &lt;code&gt;Type&lt;&#x2F;code&gt; and one for &lt;code&gt;default&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dhall&quot; class=&quot;language-dhall &quot;&gt;&lt;code class=&quot;language-dhall&quot; data-lang=&quot;dhall&quot;&gt;let rec = { Type = { b : Natural, c : Natural }, default = { b = 0, c = 0 } }

in  rec::{=}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;::{=}&lt;&#x2F;code&gt; creates the record with its default values and &lt;code&gt;::{ c = 5}&lt;&#x2F;code&gt; let’s you shallow override the defaults. It’s nice syntax sugar for creating a record with default values although you can achieve the same thing with the existing operators. I’m a fan of orthogonal features and so I’m not a big fan of this one (even though I’ve used it extensively in my own little toy project). Also this only works for records. &lt;code&gt;{ Type = Optional Natural, default = None }&lt;&#x2F;code&gt; does not compile. This means you’ll likely end up mixing defaults with syntax sugar and defaults without anyway.&lt;&#x2F;p&gt;
&lt;p&gt;There’s also a feature called &lt;a href=&quot;https:&#x2F;&#x2F;docs.dhall-lang.org&#x2F;tutorials&#x2F;Language-Tour.html#records&quot;&gt;projections&lt;&#x2F;a&gt;. It’s a bit like destructuring in languages like JS or Clojure.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dhall&quot; class=&quot;language-dhall &quot;&gt;&lt;code class=&quot;language-dhall&quot; data-lang=&quot;dhall&quot;&gt;let record = { a = 1, b = 2}

in record.{a}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the first version of this post I complained about not understanding when and how to use this, but the &lt;a href=&quot;https:&#x2F;&#x2F;discourse.dhall-lang.org&#x2F;&quot;&gt;Discourse&lt;&#x2F;a&gt; community helped me with that. Still, I don’t find this feature as useful as it could be, since it’s a bit limited where you can actually use this. Or in other words, I think I was expecting this to be the equivalent of destructuring in JS and Clojure, which it’s not:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Does not compile since that’s not how you use projections&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dhall&quot; class=&quot;language-dhall &quot;&gt;&lt;code class=&quot;language-dhall&quot; data-lang=&quot;dhall&quot;&gt;let record = { a = 1, b = 2}

in \(rec.{a} : Record) -&amp;gt; a
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Dhall doesn’t currently have actual destructuring for things like function arguments. Check out some of the discussions for such a feature at &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dhall-lang&#x2F;dhall-lang&#x2F;issues&#x2F;74&quot;&gt;GitHub&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Also note that if you need to generate a record dynamically you can &lt;a href=&quot;https:&#x2F;&#x2F;docs.dhall-lang.org&#x2F;tutorials&#x2F;Getting-started_Generate-JSON-or-YAML.html#dynamic-records&quot;&gt;actually do so&lt;&#x2F;a&gt; without having to jump through any hoops, which is pretty neat. The reason I’m not emphasizing this more is that it didn’t really come up when I was working with Dhall for &lt;code&gt;dhall-alacritty&lt;&#x2F;code&gt;, but it is something many people will want. It’s this &lt;strong&gt;attention to real world use cases&lt;&#x2F;strong&gt; that really makes Dhall shine.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ergonomics-tooling&quot;&gt;Ergonomics &amp;amp; Tooling&lt;&#x2F;h2&gt;
&lt;p&gt;I’m using &lt;code&gt;neovim&lt;&#x2F;code&gt; and the dhall language server kinda sorta works some of the time. It doesn’t have a lot of features, so it’s mostly about error checking and completion. In Visual Studio Code the experience is a bit better, but the features remain the same. The &lt;code&gt;dhall&lt;&#x2F;code&gt; binary and its subcommands is how I explore my code and ask the compiler questions about it. To me things like &lt;code&gt;dhall --annotate&lt;&#x2F;code&gt; or &lt;code&gt;dhall type&lt;&#x2F;code&gt; kind of achieve the same thing as typed holes in Haskell.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve already mentioned a couple of ways for interactively working with Dhall code throughout this post (&lt;code&gt;echo &#x27;{}&#x27; | dhall&lt;&#x2F;code&gt;, &lt;code&gt;dhall --file .&#x2F;file.dhall&lt;&#x2F;code&gt;), but there’s also &lt;code&gt;dhall repl&lt;&#x2F;code&gt; which should probably be your first choice for playing around with Dhall. It has a &lt;code&gt;:help&lt;&#x2F;code&gt; command so there’s no need for me to go through its commands.&lt;&#x2F;p&gt;
&lt;p&gt;One thing I find a bit strange is that currently &lt;code&gt;dhall format&lt;&#x2F;code&gt; removes comments. There’s an &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dhall-lang&#x2F;dhall-haskell&#x2F;issues&#x2F;145&quot;&gt;issue for that too&lt;&#x2F;a&gt; with some workarounds but it’s really annoying. Imagine introducing Dhall at work and then not easily being able to leave helpful comments for your colleagues who may be new not only to Dhall but also functional programming in general.&lt;&#x2F;p&gt;
&lt;p&gt;Error messages in Dhall are generally really good but can be a bit hit and miss in certain cases. For smaller types (meaning here not too many keys, not too nested) they show you exactly what’s wrong and are easy to interpret. In some cases they even includes helpful hints for common syntax mistakes, which reminded me a bit of Elm. For a project this young I’d say errors are mostly a shining beacon of excellence. It’s only when working with huge records that the errors become more and more cryptic, since the size of the diff (expected vs actual) to some degree mirrors the size of the record. Meaning your terminal will suddenly be filled with a wall of text and lots of &lt;code&gt;...&lt;&#x2F;code&gt; to hide some lines deemed irrelevant for the error. All in all errors are mostly really good though. For example, here’s one of those errors that also displays some helpful hints:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;r : { Type : Type, default : Optional Natural }

Error: You can only override records

Explanation: You can override records using the ❰⫽❱ operator, like this:


	┌───────────────────────────────────────────┐
	│ { foo = 1, bar = &amp;quot;ABC&amp;quot; } ⫽ { baz = True } │
	└───────────────────────────────────────────┘


	┌─────────────────────────────────────────────┐
	│ λ(r : { foo : Bool }) → r ⫽ { bar = &amp;quot;ABC&amp;quot; } │
	└─────────────────────────────────────────────┘


... but you cannot override values that are not records.

For example, the following expressions are not valid:


	┌──────────────────────────────┐
	│ { foo = 1, bar = &amp;quot;ABC&amp;quot; } ⫽ 1 │
	└──────────────────────────────┘
								 ⇧
								 Invalid: Not a record


	┌───────────────────────────────────────────┐
	│ { foo = 1, bar = &amp;quot;ABC&amp;quot; } ⫽ { baz : Bool } │
	└───────────────────────────────────────────┘
								 ⇧
								 Invalid: This is a record type and not a record


	┌───────────────────────────────────────────┐
	│ { foo = 1, bar = &amp;quot;ABC&amp;quot; } ⫽ &amp;lt; baz : Bool &amp;gt; │
	└───────────────────────────────────────────┘
								 ⇧
								 Invalid: This is a union type and not a record


────────────────────────────────────────────────────────────────────────────────

You supplied this expression as one of the arguments:

↳ None Natural

... which is not a record, but is actually a:

↳ Optional Natural

────────────────────────────────────────────────────────────────────────────────

1│                                                                r::{=}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;what-dhall-can-do-for-you&quot;&gt;What Dhall Can Do For You&lt;&#x2F;h2&gt;
&lt;p&gt;As promised, here’s an example of how I used Dhall to model the rules for key mappings in alacritty. I’d say that this is not beginner level Dhall code anymore, especially if you’re not familiar with some of the functional programming concepts in use. But I hope that it still illustrates just how much you can achieve in terms of type safety without having to do mental gymnastics and importing various PhD theses, thanks to Dhall’s focus on real world use cases.&lt;&#x2F;p&gt;
&lt;p&gt;The alacritty configuration file let’s you map keys to actions. This is fairly involved so I’ll use a slightly simplified model so the code snippets don’t blow up in size. Here’s a mapping that binds the “A” key, when “Alt” is held down as well, to the “Copy” action.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;key_bindings:
  - key: A
	mods: Alt
	action: Copy
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Modifiers and actions aren’t just random strings though. There’s a list of possible values for both, so let’s model those rules in Dhall:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dhall&quot; class=&quot;language-dhall &quot;&gt;&lt;code class=&quot;language-dhall&quot; data-lang=&quot;dhall&quot;&gt;let Modifier = &amp;lt; Alt | Control | Command &amp;gt;

let Action = &amp;lt; Copy | Paste &amp;gt;

let Binding = { mods : Optional Modifier, key : Text, action : Action }

let myBindings : List Binding =
		[ { mods = Some Modifier.Alt, key = &amp;quot;A&amp;quot;, action = Action.Copy } ]

in  myBindings
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Executing this file with &lt;code&gt;dhall-to-yaml --file .&#x2F;file.dhall&lt;&#x2F;code&gt; gives me exactly the keybinding from above (without the actual &lt;code&gt;key_bindings&lt;&#x2F;code&gt; key). Yay for more type safety! It also improves the developer experience since you now get reliable autocompletion for allowed values! There’s just one issue: this code doesn’t support multiple modifiers. It should be possible to eventually render a &lt;code&gt;.yml&lt;&#x2F;code&gt; file with an entry like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;key_bindings:
  - key: A
	mods: Alt|Shift
	action: Copy
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;mods&lt;&#x2F;code&gt; key will now have to hold a list of modifiers and then we’ll also need to create a function that turns &lt;code&gt;List Modifier&lt;&#x2F;code&gt; into &lt;code&gt;Text&lt;&#x2F;code&gt; by joining the modifiers with a &lt;code&gt;|&lt;&#x2F;code&gt;.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dhall&quot; class=&quot;language-dhall &quot;&gt;&lt;code class=&quot;language-dhall&quot; data-lang=&quot;dhall&quot;&gt;let Prelude = https:&amp;#x2F;&amp;#x2F;prelude.dhall-lang.org&amp;#x2F;package.dhall

let Modifier =
	-- List the possible modifiers we have
	&amp;lt; Alt | Control | Command &amp;gt;

let renderModifier
	: Modifier → Text
	=
	  -- Write a function that converts a single modifier to its text representation
	  λ(m : Modifier)
	  → merge { Alt = &amp;quot;Alt&amp;quot;, Control = &amp;quot;Control&amp;quot;, Command = &amp;quot;Command&amp;quot; } m

let convertModifiers
	: List Modifier → Text
	=
	  -- Convert a list of modifiers to a string where the modifiers
	  -- are joined with a pipe
	  λ(m : List Modifier)
	  → let mapped = Prelude.List.map Modifier Text renderModifier m

		let joined = Prelude.Text.concatSep &amp;quot;|&amp;quot; a

		in  joined

let Action = &amp;lt; Copy | Paste &amp;gt;

let Binding =
  -- Binding now let&amp;#x27;s you specify multiple modifiers for a given keybinding
  { mods : Optional (List Modifier), key : Text, action : Action }

let BindingRendered
	: Type
	= { mods : Optional Text, key : Text, action : Action }

let renderBinding
	: Binding → BindingRendered
	=
	  -- Use the various functions from above to convert just a
	  -- single key in Binding and then use that converted key
	  -- and value to create the rendered version of Binding
	  λ(b : Binding)
	  → let mods =
			  Prelude.Optional.map (List Modifier) Text convertModifiers b.mods

		in  { mods } &amp;#x2F;&amp;#x2F; b.{action,key}

let myBindings
	: List Binding
	= [ { mods = Some [ Modifier.Alt, Modifier.Control ]
		, key = &amp;quot;A&amp;quot;
		, action = Action.Copy
		}
	  ]

in  Prelude.List.map Binding BindingRendered renderBinding myBindings
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;😱! Let’s go through this (I also annoted the file with comments!). The definition of &lt;code&gt;Modifier&lt;&#x2F;code&gt; is the same, but I’ve added a function for converting a value of that type to text (&lt;code&gt;renderModifier&lt;&#x2F;code&gt;). It uses the aforementioned &lt;code&gt;merge&lt;&#x2F;code&gt; function which let’s you pattern match on different constructors of that union type. Here I’m simply mapping each union type value to a string (&lt;code&gt;Text&lt;&#x2F;code&gt;) of the same name.&lt;&#x2F;p&gt;
&lt;p&gt;The next function is a bit more involved, but the type signature is an excellent first thing to look at. &lt;code&gt;convertModifiers&lt;&#x2F;code&gt; takes a list of modifiers and outputs a single string. What it does is convert &lt;strong&gt;each modifier to a text then combine them all with | in between&lt;&#x2F;strong&gt;. I could also write this in a more compact manner:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;You can run this snippet by replacing &lt;code&gt;convertModifiers&lt;&#x2F;code&gt; in the snippet above&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dhall&quot; class=&quot;language-dhall &quot;&gt;&lt;code class=&quot;language-dhall&quot; data-lang=&quot;dhall&quot;&gt;let convertModifiers
	: List Modifier → Text
	= Prelude.Function.compose
		(List Modifier)
		(List Text)
		Text
		(Prelude.List.map Modifier Text renderModifier)
		(Prelude.Text.concatSep &amp;quot;|&amp;quot;)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The version using &lt;code&gt;compose&lt;&#x2F;code&gt; simply emphasises the concept of composition a bit more: the list of modifiers flows through a pipeline of “list of modifiers” -&amp;gt; “list of texts” -&amp;gt; “text”, which is just a chain of two function calls. That chain can also be expressed as the composition of these two functions. I’d always go with the more verbose and explicit version first, unless I’m working in a team where I know everyone is comfortable with composition.&lt;&#x2F;p&gt;
&lt;p&gt;Back to the bigger snippet. &lt;code&gt;Binding&lt;&#x2F;code&gt; now &lt;strong&gt;reflects the changed business logic&lt;&#x2F;strong&gt; through &lt;code&gt;List Modifier&lt;&#x2F;code&gt;, and I’ve added a rendered version of binding. Notice how I need to repeat &lt;code&gt;key&lt;&#x2F;code&gt; and &lt;code&gt;action&lt;&#x2F;code&gt; though – there’s no merge &amp;amp; override type operator.&lt;&#x2F;p&gt;
&lt;p&gt;Lastly I’m putting all of this together with &lt;code&gt;renderBinding&lt;&#x2F;code&gt;. There’s something really amazing going in there, which you may not know from other languages. Notice how inside &lt;code&gt;renderBinding&lt;&#x2F;code&gt; I’m &lt;strong&gt;never checking if a value is Some or None&lt;&#x2F;strong&gt;, even though both &lt;code&gt;Binding&lt;&#x2F;code&gt; and &lt;code&gt;BindingRendered&lt;&#x2F;code&gt; contain optional types. All of this plumbing is taken care of by &lt;code&gt;Prelude.Optional.map&lt;&#x2F;code&gt;. If you’re coming from Elm, Purescript or Haskell this will be familiar. If not, it’s like syntax sugar for &lt;code&gt;if (isSome) then doThis else doThat&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So what’s the output of the above snippets?&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;- action: Copy
  key: A
  mods: &amp;quot;Alt|Control&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Is it worth it? I think so. It’s a lot of code but it’s also a lot of safety. Everyone using that code to generate their mappings will benefit from the initial effort. To me code like this has a great multiplicative impact on others. Also some of the verbosity of Dhall comes from the fact that polymorphic functions require you to explicitly specify types. In Haskell you could simply do &lt;code&gt;map someFunc someOptional&lt;&#x2F;code&gt; and the compiler would infer the necessary types for you. In Dhall you need to explicitly state the input and output types of the &lt;code&gt;map&lt;&#x2F;code&gt; call.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;closing-thoughts&quot;&gt;Closing Thoughts&lt;&#x2F;h2&gt;
&lt;p&gt;Would I use Dhall at work? Absolutely. As I mentioned, I’m a fan of functional programming (FP). Unfortunately there’s only a single developer I’ve met in real life (outside of FP meetups) who’s interested enough in FP so that she started learning Elm on her own. There are many reasons why people aren’t as excited about FP as I’d wish for, but one of them is simply that there are lots of alternatives. If you’re doing just fine with JS, why look into something else? And that’s precisely why I think Dhall has a lot of potential to introduce a bigger audience to FP: there aren’t that many alternatives in this problem space.&lt;&#x2F;p&gt;
&lt;p&gt;Our kubernetes and helm configuration at work comes down to a mix of &lt;code&gt;.yaml&lt;&#x2F;code&gt; files with Go templating directives in strings, held together by conventions. There’s nothing which verifies the correctness of the logic in your templates. Stuff like &lt;code&gt;{{- with .Values.labels }}&lt;&#x2F;code&gt; and&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;{{- default .Chart.Name .Values.nameOverride |
  replace &amp;quot;.&amp;quot; &amp;quot;-&amp;quot; |
  lower |
  trunc 63 |
  trimSuffix &amp;quot;-&amp;quot; -}}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;is a bug waiting to happen. It’s also super exclusive. Imagine a junior developer trying to work with these files, without being able to verify that what they’re doing makes any sense. Without understanding where &lt;code&gt;.Values&lt;&#x2F;code&gt; comes from, what’s inside, what you can do with it. There’s often no explicit connection between the variable in one file and its definition in another &lt;em&gt;(I say junior developer not to belittle them – I also often don’t know exactly what values I’m working with in these files)&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Dhall isn’t the only contender in this area but in my opinion it’s the one best equipped to solve these issues. Dhall let’s you ramp up the type safety gradually, it gives you &lt;em&gt;some&lt;&#x2F;em&gt; programming features without letting you do whatever you want by limiting the language features it provides. You can improve the type safety &lt;strong&gt;and&lt;&#x2F;strong&gt; ergonomics of your configuration files with minimum effort and without any fancy types. You can also invest a lot of time and effort into making something critical as type safe as possible.&lt;&#x2F;p&gt;
&lt;p&gt;Dhall has a great and unique vision of how to apply a subset of FP to configuration files and I think it has great potential. Also you can easily learn the basiscs in a couple of hours so I’d encourage you to give it a try. The only thing you need to get started is the Dhall compiler and a terminal.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;In &lt;code&gt;bash&lt;&#x2F;code&gt; you can also use a HERE string (&lt;code&gt;&amp;lt;&amp;lt;&amp;lt;&lt;&#x2F;code&gt;) but I use &lt;code&gt;fish&lt;&#x2F;code&gt; so I’m using &lt;code&gt;echo&lt;&#x2F;code&gt; and pipe.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;At least that’s one way of doing it. You could also change the type of &lt;code&gt;mods&lt;&#x2F;code&gt; to &lt;code&gt;Text&lt;&#x2F;code&gt; and just expect people to apply some &lt;code&gt;renderListOfModifiers&lt;&#x2F;code&gt; function to their &lt;code&gt;List Modifier&lt;&#x2F;code&gt; &lt;strong&gt;before&lt;&#x2F;strong&gt; creating the &lt;code&gt;Binding&lt;&#x2F;code&gt; record.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;You are only human – Genji&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Understanding unliftio</title>
        <published>2019-05-30T00:00:00+00:00</published>
        <updated>2019-05-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://fbrs.io/unliftio/"/>
        <id>https://fbrs.io/unliftio/</id>
        
        <content type="html" xml:base="https://fbrs.io/unliftio/">&lt;p&gt;&lt;strong&gt;UPDATE 2025: &lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;cideM&#x2F;68f0be9aa4e6699a8f71d7ea81ae3490&quot;&gt;Here’s an updated gist&lt;&#x2F;a&gt; that uses a Nix shebang for a single, executable &lt;code&gt;.hs&lt;&#x2F;code&gt; file that you can run&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In this post I will go over the source code for &lt;a href=&quot;https:&#x2F;&#x2F;www.stackage.org&#x2F;package&#x2F;unliftio-core&quot;&gt;unliftio-core&lt;&#x2F;a&gt;, more specifically the &lt;code&gt;MonadUnliftIO&lt;&#x2F;code&gt; typeclass, found in &lt;code&gt;Control.Monad.IO.Unlift&lt;&#x2F;code&gt;. The typeclass is used to power the actual &lt;a href=&quot;https:&#x2F;&#x2F;www.stackage.org&#x2F;package&#x2F;unliftio&quot;&gt;unliftio&lt;&#x2F;a&gt; library, which is the one you’d use in your applications.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s start with an example (borrowed from the official docs) showing what &lt;code&gt;unliftio&lt;&#x2F;code&gt; is good for.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;unliftio-in-a-nutshell&quot;&gt;UnliftIO in a Nutshell&lt;&#x2F;h2&gt;
&lt;p&gt;You have the following function – which gives you an &lt;code&gt;IO ()&lt;&#x2F;code&gt; – but you actually need &lt;code&gt;ReaderT env IO ()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;foo :: String -&amp;gt; IO ()
foo = print
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The most straight forward and idiomatic way to translate from &lt;code&gt;IO a&lt;&#x2F;code&gt; to &lt;code&gt;m a&lt;&#x2F;code&gt; is &lt;code&gt;liftIO&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;bar :: String -&amp;gt; ReaderT env IO ()
bar = liftIO . foo
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But now you have a function where &lt;code&gt;IO&lt;&#x2F;code&gt; occurs in negative position&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; (see this &lt;a href=&quot;https:&#x2F;&#x2F;www.fpcomplete.com&#x2F;blog&#x2F;2016&#x2F;11&#x2F;covariance-contravariance&quot;&gt;post on co- and contravariance&lt;&#x2F;a&gt;), as is often the case with handlers passed in as arguments.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;foo :: (String -&amp;gt;  IO ()) -&amp;gt; IO ()
                -- ^^^^^ negative position
foo func = func &amp;quot;test&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;liftIO&lt;&#x2F;code&gt; won’t help us, but &lt;code&gt;unliftIO&lt;&#x2F;code&gt; can solve this problem.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;foo :: (String -&amp;gt;  IO ()) -&amp;gt; IO ()
                -- ^^^^^ negative position
foo func = func &amp;quot;test&amp;quot;

foo2 :: (String -&amp;gt; ReaderT String IO ())
   -&amp;gt; ReaderT String IO ()
foo2 func =
  askUnliftIO &amp;gt;&amp;gt;=
  \u -&amp;gt; liftIO $ foo (unliftIO u . func)
              -- ^^^ note that we&amp;#x27;re still calling
              -- the original `foo`. We didn&amp;#x27;t have to
              -- reimplement anything

-- Or alternatively and more concisely
foo2&amp;#x27; func =
  withRunInIO $ \runInIO -&amp;gt; foo (runInIO . func)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Both versions of &lt;code&gt;foo2&lt;&#x2F;code&gt; work. &lt;code&gt;unliftIO&lt;&#x2F;code&gt; translates from &lt;code&gt;m a&lt;&#x2F;code&gt; to &lt;code&gt;IO a&lt;&#x2F;code&gt; so that we can utilize our &lt;code&gt;ReaderT&lt;&#x2F;code&gt;, but inside a function expecting plain &lt;code&gt;IO&lt;&#x2F;code&gt;. In that sense the name “unlift” is quite fitting since it’s the opposite of lifting: it allows us to preserve the monadic context (for example the environment from a reader) but run it in &lt;code&gt;IO&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;What made me scratch my head a little was where &lt;code&gt;runInIO&lt;&#x2F;code&gt; and &lt;code&gt;u&lt;&#x2F;code&gt; came from, and how they work. Exploring those two questions is therefore the topic of this post.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;MonadUnliftIO&lt;&#x2F;code&gt; typeclass has two methods: &lt;code&gt;askUnliftIO&lt;&#x2F;code&gt; and &lt;code&gt;withRunInIO&lt;&#x2F;code&gt;, either of which suffices for a minimal implementation. We’ll go over both, so let’s start with &lt;code&gt;askUnliftIO&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;askunliftio&quot;&gt;askUnliftIO&lt;&#x2F;h2&gt;
&lt;p&gt;This method has the function signature &lt;code&gt;m (UnliftIO m)&lt;&#x2F;code&gt; and returns a newtype wrapper (shown below), which, according to the documentation, exists because&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;We need to new datatype (instead of simply using a forall) due to lack of support in GHC for impredicative types.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;newtype UnliftIO m = UnliftIO
  { unliftIO :: forall a. m a -&amp;gt; IO a
  }
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you’re as baffled by &lt;a href=&quot;https:&#x2F;&#x2F;wiki.haskell.org&#x2F;Impredicative_types&quot;&gt;impredicative types&lt;&#x2F;a&gt; as I was, feel free to peruse the link. Or don’t, because it’s not necessary to understand how &lt;code&gt;unliftio&lt;&#x2F;code&gt; works. You can actually ignore the newtype wrapper entirely, for the purposes of understanding how the library works, since it’s purely an implementation detail.&lt;&#x2F;p&gt;
&lt;p&gt;To make it easier to follow along, I created &lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;cideM&#x2F;aa69df23cf8cb50295ed629f2432d6a6&quot;&gt;a gist&lt;&#x2F;a&gt; with a Haskell script that you can simply save somewhere and then load into &lt;code&gt;ghci&lt;&#x2F;code&gt;. Note that I’m not importing &lt;code&gt;unliftio&lt;&#x2F;code&gt;, instead I simply copy &amp;amp; pasted the minimal, relevant bits from the source code.&lt;&#x2F;p&gt;
&lt;p&gt;We have two instances for &lt;code&gt;MonadUnliftIO&lt;&#x2F;code&gt; in this file, one for &lt;code&gt;ReaderT&lt;&#x2F;code&gt; and one for &lt;code&gt;IO&lt;&#x2F;code&gt;. The latter isn’t very interesting, since it’s more or less just the identity function. We’ll therefore focus on the former:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;instance MonadUnliftIO m =&amp;gt;
  MonadUnliftIO (ReaderT r m) where
  askUnliftIO =
  ReaderT $ \env -&amp;gt;
    askUnliftIO &amp;gt;&amp;gt;= \newtypeU -&amp;gt;
    let unlift = unliftIO newtypeU
     in liftIO $ return
       (UnliftIO (unlift . flip runReaderT env))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The function signature of &lt;code&gt;askUnliftIO&lt;&#x2F;code&gt; specialized to reader is &lt;code&gt;ReaderT r m (UnliftIO (ReaderT r m))&lt;&#x2F;code&gt;. Since we need to stay in the &lt;code&gt;ReaderT&lt;&#x2F;code&gt; monad, the function body starts by creating a new &lt;code&gt;ReaderT&lt;&#x2F;code&gt;. More precisely, and also how the docs formulate it, we’re &lt;em&gt;preserving the reader’s monadic context&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In the function passed to the &lt;code&gt;ReaderT&lt;&#x2F;code&gt; constructor, we use &lt;code&gt;askUnliftIO&lt;&#x2F;code&gt; yet again, but this time it’s the instance of the monad inside our reader (the &lt;code&gt;m&lt;&#x2F;code&gt; in &lt;code&gt;ReaderT r m&lt;&#x2F;code&gt;). That’s why there is a type class constraint, mandating that &lt;code&gt;m&lt;&#x2F;code&gt; also implements &lt;code&gt;MonadUnliftIO&lt;&#x2F;code&gt;. This kind of unwrapping our monad layers by invoking the instance for the next layer is a pretty important concept which can be seen in many libraries.&lt;&#x2F;p&gt;
&lt;p&gt;Since we’re using monadic bind &lt;code&gt;&amp;gt;&amp;gt;=&lt;&#x2F;code&gt;, the inner most function will get the &lt;code&gt;UnliftIO m&lt;&#x2F;code&gt; part from &lt;code&gt;m (UnliftIO m)&lt;&#x2F;code&gt;, which is called &lt;code&gt;newTypeU&lt;&#x2F;code&gt; in the snippet. Once unwrapped, this gives us the &lt;strong&gt;actual function to unlift&lt;&#x2F;strong&gt; something from &lt;code&gt;m a&lt;&#x2F;code&gt; to &lt;code&gt;IO a&lt;&#x2F;code&gt; – here called &lt;code&gt;unlift&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Quick reminder about the syntax here: the &lt;code&gt;UnliftIO&lt;&#x2F;code&gt; newtype is a record with a single field called &lt;code&gt;unliftIO&lt;&#x2F;code&gt;. To get that field’s content from the record, we apply the &lt;code&gt;unliftIO&lt;&#x2F;code&gt; function to the record – just like with any other record in Haskell!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;That unlift function is used in the final line of the snippet where we first run our reader (remember that we want to preserve the monadic context) and then pass the result to our &lt;code&gt;unlift&lt;&#x2F;code&gt; function. In our case with &lt;code&gt;ReaderT env IO&lt;&#x2F;code&gt;, that &lt;code&gt;unlift&lt;&#x2F;code&gt; is &lt;strong&gt;just the identity function&lt;&#x2F;strong&gt;, since that’s how the unlift instance is defined for &lt;code&gt;IO&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;instance MonadUnliftIO IO where
  askUnliftIO = return (UnliftIO id)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In other words, composing the two functions creates a new function which takes a monad (&lt;code&gt;ReaderT&lt;&#x2F;code&gt;) and outputs an &lt;code&gt;IO&lt;&#x2F;code&gt;, which is exactly the signature (&lt;code&gt;m a -&amp;gt; IO a&lt;&#x2F;code&gt; ) we need. We then package that composed function up in &lt;code&gt;UnliftIO&lt;&#x2F;code&gt;, and return a lifted version of it. &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;&#x2F;strong&gt;: What this achieves is that calling &lt;code&gt;askUnliftIO&lt;&#x2F;code&gt; on a reader&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;calls &lt;code&gt;askUnliftIO&lt;&#x2F;code&gt; of the monad inside the reader to recursively unwrap the monad layers until we get to IO&lt;&#x2F;li&gt;
&lt;li&gt;runs the reader (its monadic context)&lt;&#x2F;li&gt;
&lt;li&gt;repackages it all in a reader and in an &lt;code&gt;UnliftIO&lt;&#x2F;code&gt;, giving us an unlift function&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;One thing that helps tremendously is to just add type annotations everywhere and let GHC check if our assumptions are correct. If you’re ever stuck and can’t figure out the type signature of something, just replace it with a wildcard&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; and see what GHC suggests. Here’s the above code snippet but with types sprinkled all over it. Note that this snippet &lt;em&gt;requires the &lt;code&gt;{-# LANGUAGE InstanceSigs #-}&lt;&#x2F;code&gt; pragma&lt;&#x2F;em&gt;!&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;instance MonadUnliftIO m =&amp;gt; MonadUnliftIO (ReaderT r m) where
  askUnliftIO :: ReaderT r m (UnliftIO (ReaderT r m))
  askUnliftIO = ReaderT f
  where
    f env =
    (askUnliftIO :: m (UnliftIO m)) &amp;gt;&amp;gt;= \(u :: UnliftIO m) -&amp;gt;
      let unlift = (unliftIO u :: m a -&amp;gt; IO a)
        unlift&amp;#x27; =
        (unlift . (flip runReaderT env :: ReaderT r m a1 -&amp;gt; m a1))
        returned =
        return (UnliftIO unlift&amp;#x27;) :: IO (UnliftIO (ReaderT r m))
       in liftIO returned :: m (UnliftIO (ReaderT r m))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;withruninio&quot;&gt;withRunInIO&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;code&gt;withRunInIO&lt;&#x2F;code&gt; function removes a bit of the plumbing that &lt;code&gt;askUnliftIO&lt;&#x2F;code&gt; requires and let’s you write code that is even more concise than &lt;code&gt;askUnliftIO&lt;&#x2F;code&gt; (as can be seen from the example at the end of the first chapter).&lt;&#x2F;p&gt;
&lt;p&gt;Its function signature is&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;((forall a. m a -&amp;gt; IO a) -&amp;gt; IO b) -&amp;gt; m b
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;but for simplicity’s sake I won’t include the &lt;code&gt;forall&lt;&#x2F;code&gt; part in future references to the signature. As you can see, it takes only a single argument, which is a callback.&lt;&#x2F;p&gt;
&lt;p&gt;Just as with &lt;code&gt;askUnliftIO&lt;&#x2F;code&gt;, the &lt;code&gt;IO&lt;&#x2F;code&gt; instance is pretty boring, so we’ll jump straight to our familiar &lt;code&gt;ReaderT&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The basic layout is quite similar as for &lt;code&gt;askUnliftIO&lt;&#x2F;code&gt;: We’re returning a &lt;code&gt;ReaderT&lt;&#x2F;code&gt;, and inside the function passed to the constructor we’re calling &lt;code&gt;withRunInIO&lt;&#x2F;code&gt;. This uses the &lt;code&gt;withRunInIO&lt;&#x2F;code&gt; instance from whatever monad we’re using in the reader. Hence the type class constraint for the monad used in the reader. But there is one important difference: &lt;code&gt;withRunInIO&lt;&#x2F;code&gt; takes an argument, which is called &lt;code&gt;inner&lt;&#x2F;code&gt; in the code snippets.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;withRunInIO inner =
  ReaderT $ \env -&amp;gt;
  withRunInIO $ \runInIO -&amp;gt;
    inner (runInIO . flip runReaderT env)

foo2&amp;#x27; func = withRunInIO $
  \runInIO -&amp;gt; foo (runInIO . func)
-- ^^^^^^^ That&amp;#x27;s the (runInIO . flip runReaderT env) part
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inner
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I copied the snippet from the first chapter, so it’s easier to see how &lt;code&gt;foo2&#x27;&lt;&#x2F;code&gt; is passing a callback to &lt;code&gt;withRunInIO&lt;&#x2F;code&gt;, which is what we refer to as &lt;code&gt;inner&lt;&#x2F;code&gt;. That function also receives a callback (here called &lt;code&gt;runInIO&lt;&#x2F;code&gt;), which does exactly the same as the &lt;code&gt;unlift&lt;&#x2F;code&gt; function we pulled out of the &lt;code&gt;UnliftIO&lt;&#x2F;code&gt; newtype in the last chapter.&lt;&#x2F;p&gt;
&lt;p&gt;The basic mechanism is exactly the same: peel off the monad layers, delegating to the &lt;code&gt;UnliftIO&lt;&#x2F;code&gt; instance of each layer, until we eventually reach &lt;code&gt;IO&lt;&#x2F;code&gt;. &lt;code&gt;withRunInIO&lt;&#x2F;code&gt; is just a bit more concise.&lt;&#x2F;p&gt;
&lt;p&gt;Here’s the reader instance with type annotations:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;instance MonadUnliftIO m =&amp;gt;
  MonadUnliftIO (ReaderT r m) where
  withRunInIO
  :: ((forall a. ReaderT r m a -&amp;gt; IO a) -&amp;gt; IO b)
  -&amp;gt; ReaderT r m b
  withRunInIO inner =
  ReaderT $ \env -&amp;gt;
    -- withRunInIO
    -- :: ((forall a. m a -&amp;gt; IO a) -&amp;gt; IO b)
    -- -&amp;gt; m b
    withRunInIO $ \runInIO -&amp;gt;
        -- runInIO          |   flip runReaderT env
        -- :: forall a. m a |   :: ReaderT r m a
        -- -&amp;gt; IO a          |   -&amp;gt; m a
      inner (runInIO          .   flip runReaderT env)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;what-now&quot;&gt;What Now?&lt;&#x2F;h2&gt;
&lt;p&gt;The goal of this post was to understand how &lt;code&gt;unliftio-core&lt;&#x2F;code&gt; works on a basic level. Consider it an intellectual exercise for non-experts (like me) to understand how other people write their Haskell libraries. For information on how this library treats async exceptions or handling the state monad in relation to cleanup handlers, please see the official documentation.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;unliftio&lt;&#x2F;code&gt; library re-exports a lot of modules, none of which I looked at in this post. That’s because once you understand the concept, the implementation of most (all?) of these re-exported modules is fairly mechanical. See for example this random snippet from &lt;code&gt;UnliftIO.Process&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;withCreateProcess ::
   MonadUnliftIO m
  =&amp;gt; CreateProcess
  -&amp;gt; (Maybe Handle
    -&amp;gt; Maybe Handle
    -&amp;gt; Maybe Handle
    -&amp;gt; ProcessHandle
    -&amp;gt; m a)
  -&amp;gt; m a
withCreateProcess c action =
  withRunInIO
  (\u -&amp;gt;
     P.withCreateProcess
     c
     (\stdin_h stdout_h stderr_h proc_h -&amp;gt;
      u (action stdin_h stdout_h stderr_h proc_h)))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Hopefully it’s easy to see the familiar pattern of passing a callback to &lt;code&gt;withRunInIO&lt;&#x2F;code&gt;, where you then have access to an unlift function, thanks to the type class constraint.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;code&gt;IO&lt;&#x2F;code&gt; also occurs in positive position.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Technically the &lt;code&gt;liftIO&lt;&#x2F;code&gt; isn’t necessary for this specific use case. Since we’re in the &lt;code&gt;IO&lt;&#x2F;code&gt; monad anyway, &lt;code&gt;liftIO&lt;&#x2F;code&gt; is superfluous here.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;code&gt;foo :: _; foo s = s ++ s&lt;&#x2F;code&gt; gives “Found type wildcard ‘_’ standing for ‘[a] -&amp;gt; [a]’” which we can then use in the signature.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Compose Newtype and its Applicative Instance</title>
        <published>2019-03-27T00:00:00+00:00</published>
        <updated>2019-03-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://fbrs.io/applicative-compose/"/>
        <id>https://fbrs.io/applicative-compose/</id>
        
        <content type="html" xml:base="https://fbrs.io/applicative-compose/">&lt;p&gt;When I went through &lt;em&gt;Haskell From First Principle&lt;&#x2F;em&gt; the first time, I struggled with the &lt;code&gt;Compose&lt;&#x2F;code&gt; applicative instance, which is part of an exercise in chapter 25. This post will give you a quick overview of the &lt;code&gt;Compose&lt;&#x2F;code&gt; data type and then explain how the applicative instance for that type works.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;Compose&lt;&#x2F;code&gt; data type is &lt;a href=&quot;http:&#x2F;&#x2F;hackage.haskell.org&#x2F;package&#x2F;base-4.12.0.0&#x2F;docs&#x2F;Data-Functor-Compose.html&quot;&gt;part of base&lt;&#x2F;a&gt; and allows composing two functors:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&amp;gt; :m Data.Functor.Compose
&amp;gt; let a = Right (Just 2)
&amp;gt; :t Compose a
&amp;gt; Compose a :: Num a =&amp;gt; Compose (Either a2) Maybe a
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;Any code that starts with &lt;code&gt;&amp;gt;&lt;&#x2F;code&gt; is meant to be run in a repl, such as &lt;code&gt;stack ghci&lt;&#x2F;code&gt; or &lt;code&gt;ghci&lt;&#x2F;code&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Here we took two functors (a &lt;code&gt;Maybe&lt;&#x2F;code&gt; and an &lt;code&gt;Either&lt;&#x2F;code&gt;) and composed them, giving us a new functor! Why is that useful?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&amp;gt; :m Data.Functor.Compose
&amp;gt; let a = Right (Just 2)
&amp;gt; fmap ((+) 2) a
• No instance for (Num (Maybe Int)) arising from a use of ‘+’
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This does not work because &lt;code&gt;fmap&lt;&#x2F;code&gt; is trying to map &lt;code&gt;(+) 2&lt;&#x2F;code&gt; over our &lt;code&gt;Either&lt;&#x2F;code&gt;, which is equivalent to applying &lt;code&gt;(+) 2&lt;&#x2F;code&gt; to &lt;code&gt;Just 2&lt;&#x2F;code&gt; which doesn’t work. However, with the help of &lt;code&gt;Compose&lt;&#x2F;code&gt; we can create a new functor from &lt;code&gt;Either&lt;&#x2F;code&gt; and &lt;code&gt;Maybe&lt;&#x2F;code&gt; which will work with &lt;code&gt;fmap&lt;&#x2F;code&gt;!&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&amp;gt; :m Data.Functor.Compose
&amp;gt; let a = Right (Just 2)
&amp;gt; let b = Compose a
&amp;gt; fmap ((+) 2) b
Compose (Right (Just 4))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;&#x2F;h2&gt;
&lt;p&gt;In the book, you’re tasked with writing the applicative instance for &lt;code&gt;Compose&lt;&#x2F;code&gt;, which requires at least two functions&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;: &lt;code&gt;pure&lt;&#x2F;code&gt; and &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;pure :: a -&amp;gt; fa a
(&amp;lt;*&amp;gt;) :: fa (a -&amp;gt; b) -&amp;gt; fa a -&amp;gt; fa b
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I really struggled with the definition of &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt;, so I turned to google to find some solutions that I could then reverse engineer. Here’s one possible definition:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;instance (Applicative fa, Applicative fb) =&amp;gt;
  Applicative (Compose fa fb) where
  (&amp;lt;*&amp;gt;) ::
	   Compose fa fb (a -&amp;gt; b)
	-&amp;gt; Compose fa fb a
	-&amp;gt; Compose fa fb b
  Compose x &amp;lt;*&amp;gt; Compose y =
	Compose ((&amp;lt;*&amp;gt;) &amp;lt;$&amp;gt; x &amp;lt;*&amp;gt; y)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;Functor types are named fa, fb, and so on. If you see an f, it’s a function, both on the type and the data level. I refer to fa and fb as functors since the applicative type class requires those things to be functors.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;As is often the case with Haskell, the code is really concise. In a single line we’re dealing with three operators and one of them is the very operator we’re defining for &lt;code&gt;Compose&lt;&#x2F;code&gt; (&lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt;). While that kind of code is a joy to read and write if you’re fluent in all things functor and applicative, it’s a mouthful if you’re trying to improve your understanding of these topics.&lt;&#x2F;p&gt;
&lt;p&gt;So let’s work through the implementation one step at a time!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;something-concrete&quot;&gt;Something Concrete&lt;&#x2F;h2&gt;
&lt;p&gt;The code below shows a function &lt;code&gt;(+) 2&lt;&#x2F;code&gt; wrapped in a &lt;code&gt;Maybe&lt;&#x2F;code&gt;. We apply it to a value (wrapped in a &lt;code&gt;Maybe&lt;&#x2F;code&gt;) by using &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt;. Simple enough.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&amp;gt; let a = Just ((+) 2)
&amp;gt; let b = Just 5
&amp;gt; a &amp;lt;*&amp;gt; b
Just 7

	   Just ((+) 2)     Just 5    Just 7
&amp;lt;*&amp;gt; :: fa   (a -&amp;gt; b) -&amp;gt; fa   a -&amp;gt; fa   b
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let’s up the ante a bit and wrap both the function and the value in another &lt;code&gt;Maybe&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&amp;gt; let a = Just (Just ((+) 2))
&amp;gt; let b = Just (Just 5)
&amp;gt; a &amp;lt;*&amp;gt; b
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This does not work since we can’t just add another layer and expect the original &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt; to work. After all, its type signature expects function and value to be inside a single functor, not nested in another.&lt;&#x2F;p&gt;
&lt;p&gt;So what’s the #1 solution for manipulating nested stuff in Haskell? &lt;code&gt;fmap&lt;&#x2F;code&gt; all the things!&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&amp;gt; :m Control.Applicative
&amp;gt; let a = Just (Just ((+) 2))
&amp;gt; let b = Just (Just 5)
&amp;gt; fmap (&amp;lt;*&amp;gt;) a &amp;lt;*&amp;gt; b
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We map &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt; over &lt;code&gt;a&lt;&#x2F;code&gt;, meaning we partially apply &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt; to the &lt;code&gt;Just ((+) 2)&lt;&#x2F;code&gt; inside &lt;code&gt;a&lt;&#x2F;code&gt;. We then take that partially applied function (which is still inside the functor &lt;code&gt;a&lt;&#x2F;code&gt;) and apply it to the &lt;code&gt;Just 5&lt;&#x2F;code&gt; in &lt;code&gt;b&lt;&#x2F;code&gt;. Please go ahead and open a repl now and play around with that code, it can do wonders for understanding stuff like that.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;something-abstract&quot;&gt;Something Abstract&lt;&#x2F;h2&gt;
&lt;p&gt;But how does the &lt;code&gt;fmap&lt;&#x2F;code&gt; knowledge from the last paragraph help us make sense of the instance code?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;instance (Applicative fa, Applicative fb) =&amp;gt;
  Applicative (Compose fa fb) where
  (&amp;lt;*&amp;gt;) ::
	   Compose fa fb (a -&amp;gt; b)
	-&amp;gt; Compose fa fb a
	-&amp;gt; Compose fa fb b
  Compose x &amp;lt;*&amp;gt; Compose y =
	Compose ((&amp;lt;*&amp;gt;) &amp;lt;$&amp;gt; x &amp;lt;*&amp;gt; y)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first part &lt;code&gt;(&amp;lt;*&amp;gt;) &amp;lt;$&amp;gt; x&lt;&#x2F;code&gt; written without infix notation and &lt;code&gt;fmap&lt;&#x2F;code&gt; instead of the operator is &lt;code&gt;fmap (&amp;lt;*&amp;gt;) x&lt;&#x2F;code&gt;. We map the function &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt; over &lt;code&gt;x&lt;&#x2F;code&gt; and &lt;code&gt;x&lt;&#x2F;code&gt; has the type &lt;code&gt;fa fb (a -&amp;gt; b)&lt;&#x2F;code&gt;. We therefore apply &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt; to the &lt;code&gt;fb (a -&amp;gt; b)&lt;&#x2F;code&gt; inside &lt;code&gt;x&lt;&#x2F;code&gt;. Check out the commented code below, which hopefully makes things clearer.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;instance (Applicative fa, Applicative fb) =&amp;gt;
  Applicative (Compose fa fb) where
	(&amp;lt;*&amp;gt;) ::
		  Compose fa fb (a -&amp;gt; b)
				 --  ^^^^^^^^^^^
				 -- This is the first argument to &amp;lt;*&amp;gt;
	   -&amp;gt; Compose fa fb a
	   -&amp;gt; Compose fa fb b
	Compose x &amp;lt;*&amp;gt; Compose y =
		-- fa&amp;#x27; :: fa (fb a -&amp;gt; fb b)
		--            ^^^^ The 2nd argument to &amp;lt;*&amp;gt;
		let fa&amp;#x27; = fmap (&amp;lt;*&amp;gt;) x
			   -- ^^^^ mapping &amp;lt;*&amp;gt; over x means applying
			   -- &amp;lt;*&amp;gt; to the content of x
		in ???
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt; only needs its 2nd argument now, which is a functor with a value inside it. And we have something like that &lt;strong&gt;inside&lt;&#x2F;strong&gt; our &lt;code&gt;y&lt;&#x2F;code&gt; (&lt;code&gt;y&lt;&#x2F;code&gt; is &lt;code&gt;fa fb b&lt;&#x2F;code&gt; and therefore the missing argument to &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt; is the &lt;code&gt;fb b&lt;&#x2F;code&gt; part inside the &lt;code&gt;fa&lt;&#x2F;code&gt;). How can we apply a function inside a functor to a value inside a functor? &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt;! And that’s how we arrive at the 2nd part:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;instance (Applicative fa, Applicative fb) =&amp;gt;
  Applicative (Compose fa fb) where
	(&amp;lt;*&amp;gt;) ::
		  Compose fa fb (a -&amp;gt; b)
	   -&amp;gt; Compose fa fb a
	   -&amp;gt; Compose fa fb b
	Compose x &amp;lt;*&amp;gt; Compose y =
		let fa&amp;#x27; = fmap (&amp;lt;*&amp;gt;) x
		in Compose $ fa&amp;#x27; &amp;lt;*&amp;gt; y
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is not so different from how we used &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt; in “Something Concrete”, just that both arguments have an additional level of nesting. Aligning the type signatures of &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt; (top) and &lt;code&gt;Compose x &amp;lt;*&amp;gt; Compose y&lt;&#x2F;code&gt; (bottom) helps with visualising the similarities. It’s the exact same operation one level deeper for both arguments.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;   fb (a -&amp;gt; b) -&amp;gt;    fb a -&amp;gt;    fb b
fa fb (a -&amp;gt; b) -&amp;gt; fa fb a -&amp;gt; fa fb b
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Quick recap:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fmap (&amp;lt;*&amp;gt;) x&lt;&#x2F;code&gt;: Partially apply &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt; the contents of &lt;code&gt;x&lt;&#x2F;code&gt;, which gives us a functor holding a partially applied function.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;fa&#x27; &amp;lt;*&amp;gt; y&lt;&#x2F;code&gt;: Fully apply the &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt; inside &lt;code&gt;fa&#x27;&lt;&#x2F;code&gt; (!) to the contents of &lt;code&gt;y&lt;&#x2F;code&gt; through another use of &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;the-hackage-implementation&quot;&gt;The hackage implementation&lt;&#x2F;h2&gt;
&lt;p&gt;The implementation of the applicative instance using &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt; and a mix of infix operators requires some mental gymnastics. On &lt;a href=&quot;http:&#x2F;&#x2F;hackage.haskell.org&#x2F;package&#x2F;base-4.12.0.0&#x2F;docs&#x2F;src&#x2F;Data.Functor.Compose.html#line-112&quot;&gt;hackage&lt;&#x2F;a&gt; however the instance uses &lt;code&gt;liftA2&lt;&#x2F;code&gt;, which does a much better job of communicating the essence of what’s going on. Here’s an example of how &lt;code&gt;liftA2&lt;&#x2F;code&gt; works, and where it’s compared to our use of &lt;code&gt;liftA&lt;&#x2F;code&gt; from above.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&amp;gt; let a = Just (Just ((+) 2))
&amp;gt; let b = Just (Just 5)
&amp;gt; fmap (&amp;lt;*&amp;gt;) a &amp;lt;*&amp;gt; b
Just (Just 7)
&amp;gt; liftA (&amp;lt;*&amp;gt;) a &amp;lt;*&amp;gt; b
Just (Just 7)
&amp;gt; liftA2 (&amp;lt;*&amp;gt;) a b
Just (Just 7)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As you can see, &lt;code&gt;liftA2&lt;&#x2F;code&gt; leads to the same result but is a bit more concise and expressive in this case. We can use &lt;code&gt;liftA2&lt;&#x2F;code&gt; to conveniently apply &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt; to the contents of the two functors in the two &lt;code&gt;Compose&lt;&#x2F;code&gt; types.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;edit&quot;&gt;Edit&lt;&#x2F;h2&gt;
&lt;p&gt;Thanks to &lt;code&gt;u&#x2F;Syrak&lt;&#x2F;code&gt; from reddit for reminding me that &lt;code&gt;liftA&lt;&#x2F;code&gt; and &lt;code&gt;fmap&lt;&#x2F;code&gt; are pretty much the same. I edited the post so that &lt;code&gt;liftA&lt;&#x2F;code&gt; is only used at the very end. See also &lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;haskell&#x2F;comments&#x2F;b8067x&#x2F;blog_post_the_compose_newtype_and_its_applicative&#x2F;ejvt62y?utm_source=share&amp;amp;utm_medium=web2x&quot;&gt;his comment&lt;&#x2F;a&gt; for more insights!&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Technically the minimal definition of applicative requires &lt;code&gt;pure&lt;&#x2F;code&gt; and either &lt;code&gt;&amp;lt;*&amp;gt;&lt;&#x2F;code&gt; or &lt;code&gt;liftA2&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
</feed>
