<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title></title>
<link>https://ediblemonad.dev/home</link>
<language>en-us</language>
<image><url>https://ediblemonad.dev/logo.png</url>
<title>Ediblemonad</title>
<link>https://ediblemonad.dev</link></image>

<item><guid>2026-10-05-kph40-is-fun</guid>
<title>KPH40 is fun</title>
<link>https://ediblemonad.dev/music/2026-10-05-kph40-is-fun</link>
<comments>https://ediblemonad.dev/music/2026-10-05-kph40-is-fun</comments>
<pubDate>2026-10-05</pubDate>
<description>
<![CDATA[
<h1 id="kph40-is-fun">KPH40 is fun</h1>
<p>Got Koss KPH40 utility recently and it's pretty fun. It's not as loud
as I'd like but the sound quality is quite good. Pretty good detail with
suprisingly decent bass. A tiny bit of sound-leak but not that bad. Sits
quite comfortably on the head.</p>
<p>Whatever. We all know this already. That's already talked about but 1
criteria nobody mentions is headbangability. I was an IEM person for the
most part because I move my head a lot when music plays. KPH40 stays on
my head fine but for a violent enough head shake, it starts moving. It
survives mild desk headbanging pretty well but, not as good as an
IEM.</p>
<p>6/10 headbangable. Up next, my review on condom
helicopterability.</p>

]]>
</description></item>
<item><guid>2026-06-06-spotify-can-suck-it</guid>
<title>Fuck spotify</title>
<link>https://ediblemonad.dev/music/2026-06-06-spotify-can-suck-it</link>
<comments>https://ediblemonad.dev/music/2026-06-06-spotify-can-suck-it</comments>
<pubDate>2026-06-06</pubDate>
<description>
<![CDATA[
<h1 id="fuck-spotify">Fuck spotify</h1>
<p>It's not breaking news that a lot of subscription services are
predatory towards their customers. But spotify taskes it a step further
and is predatory towards their artists as well. And thats just for the
popular artists, newer artists and niche ones cannot survive with
this.</p>
<p>Why am I avoiding piracy if the artists still barely get paid? Answer
my question, Lars!</p>
<p>In exchange they offer convinience to both sides. Is that really
worth it? I thought so for a while too but then I started feeling
uncomfortable with the whole thing.</p>
<p>So what are the alternatives? Theres a lot of good options but the
technicality and time spent evaluating the options might put off some
people.</p>
<ul>
<li>Self-hosted music streaming server:
<a target="_blank _parent" rel="noopener" href="https://jellyfin.org/">jellyfin
server</a>,
<a target="_blank _parent" rel="noopener" href="https://mopidy.com/">mopidy</a>,
<a target="_blank _parent" rel="noopener" href="https://www.navidrome.org/">navidrome</a>,
<a target="_blank _parent" rel="noopener" href="https://github.com/epoupon/lms">LMS</a></li>
<li>Music client:
<a target="_blank _parent" rel="noopener" href="https://www.symfonium.app/">Symfonium</a>,
<a target="_blank _parent" rel="noopener" href="https://mopidy.com/ext/iris/">mopidy-iris
(for mopidy)</a>,
<a target="_blank _parent" rel="noopener" href="https://jellyfin.org/">jellyfin
client</a>
<a target="_blank _parent" rel="noopener" href="https://github.com/UnicornsOnLSD/finamp">Finamp
(for jellyfin)</a></li>
<li>Self-hosted music discovery:
<a target="_blank _parent" rel="noopener" href="https://github.com/LumePart/Explo">explo</a>
+
<a target="_blank _parent" rel="noopener" href="https://listenbrainz.org/">listenbrainz</a></li>
<li>Purchasing music:
<a target="_blank _parent" rel="noopener" href="https://bandcamp.com/">bandcamp</a>,
<a target="_blank _parent" rel="noopener" href="https://www.qobuz.com"><a
href="https://www.qobuz.com">https://www.qobuz.com</a></a></li>
</ul>
<p>This path is way more accessible and convinient than it might seem at
first.</p>
<p>Another much simpler alternative is to use a physical music player
(or just your phone) and load all your music files in there. I use a
snowsky echo mini which has an sd card with all the albums I own (flacs
from bandcamp) which is a fair compromise for me.</p>
<p>Spotify can suck it.</p>

]]>
</description></item>
<item><guid>2026-05-02-mr-bungle-is-real-fart</guid>
<title>Mr. Bungle is real art</title>
<link>https://ediblemonad.dev/music/2026-05-02-mr-bungle-is-real-fart</link>
<comments>https://ediblemonad.dev/music/2026-05-02-mr-bungle-is-real-fart</comments>
<pubDate>2026-05-02</pubDate>
<description>
<![CDATA[
<h1 id="mr-bungle-is-real-art">Mr. Bungle is real art</h1>
<p>A band like Mr. Bungle is rare because given how hard it is to make
enough money to survive as a band, I'm surprised how more bands don't
lean towards mass appeal. But Mr. Bungle is comfortable with just
finding an identity in making the songs that they want to make, even if
that identity involves including
<a target="_blank _parent" rel="noopener" href="https://youtu.be/nE6UUg0Nenc?si=-g8dWEof9tVkZWoG&t=448">the
track 'Noises'</a> in your album.</p>
<p>For people who want to get into them, the album order I enjoy is
California -&gt; Mr. Bungle -&gt; Disco Volante -&gt; everything after
that. To me that is ordered by weirdness because I like starting
comfortable.</p>

]]>
</description></item>
<item><guid>2026-10-03-rss-is-dead</guid>
<title>RSS is dead</title>
<link>https://ediblemonad.dev/tools/2026-10-03-rss-is-dead</link>
<comments>https://ediblemonad.dev/tools/2026-10-03-rss-is-dead</comments>
<pubDate>2026-10-03</pubDate>
<description>
<![CDATA[
<h1 id="rss-is-dead">RSS is dead</h1>
<p>Reddit decided to kill their <a
href="https://techcrunch.com/2026/09/30/reddit-is-killing-rss-feeds-ending-public-api-access-because-of-ai-bots/">RSS
feed</a>. They say AI and scraping but that translates to "only we
should make money off selling user content here". That was also the
reason why they priced their public API to death previously and now
that's killed for real as well. I think the internet as a whole is
turning hostile towards people that want to consume content on their own
terms. This is because of the sudden inflation of the value of user data
caused by AI's presence. Before it used to just be about selling user
data for targetted ads, now it's all about AI, baybee. So I wouldn't be
surprised if more public RSS feeds and APIs start disappearing and
eventually the only way to interact with the internet would be via AI
and summaries of inaccessible information. A few big AI companies become
the only medium for the internet and privacy becomes the thing we get
all nostalgic thinking about. We're kinda fucked.</p>

]]>
</description></item>
<item><guid>2026-07-02-normalize-official-rss-feeds</guid>
<title>Normalize official RSS feeds</title>
<link>https://ediblemonad.dev/tools/2026-07-02-normalize-official-rss-feeds</link>
<comments>https://ediblemonad.dev/tools/2026-07-02-normalize-official-rss-feeds</comments>
<pubDate>2026-07-02</pubDate>
<description>
<![CDATA[
<h1 id="normalize-official-rss-feeds">Normalize official RSS feeds</h1>
<p>Given the shitshow every single medium of accessing information and
entertainment feeds has turned into with organizations optimizing the
amount of time people spend on their apps, I think we need more neutral
sources. Source that are not trying to "understand" us to manipulate us
into using their app more like the most toxic relationship. RSS seems
like the only good standard left for this. I really like that youtube
and reddit have official rss feeds which I use a lot. And I'm also very
happy with the amount of blogs I've found that provide an rss feed. But
we could definitely use more of this. We also need to normalize it's use
to the point where people lean towards rss instinctively rather than
reaching for the apps/websites.</p>

]]>
</description></item>
<item><guid>2026-06-27-kakoune--snippets</guid>
<title>Kakoune: snippets</title>
<link>https://ediblemonad.dev/tools/2026-06-27-kakoune--snippets</link>
<comments>https://ediblemonad.dev/tools/2026-06-27-kakoune--snippets</comments>
<pubDate>2026-06-27</pubDate>
<description>
<![CDATA[
<h1 id="kakoune-snippets">Kakoune: snippets</h1>
<p>Kakoune doesn't have built-in support for snippets. You can use
plugins like
<a target="_blank _parent" rel="noopener" href="https://github.com/occivink/kakoune-snippets">occivink/kakoune-snippets</a>
to have that in the editor but you could also have a much simpler setup
for snippets with a few lines of scripting.</p>
<p>My first iteration of snippets was just to use commands and prompt
for input like so:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">declare-option</span> <span class="at">-hidden</span> str-list snippets_list</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ex">define-command</span> snippets-insert %{</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  <span class="ex">prompt</span> <span class="at">-menu</span> <span class="st">&#39;Snippets: &#39;</span> <span class="dt">\</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="at">-shell-script-candidates</span> <span class="st">&#39;echo &quot;$kak_opt_snippet_list&quot;&#39;</span> <span class="dt">\</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    %{ evaluate-commands %val{text} }</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="er">}</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="ex">define-command</span> define-snippet <span class="at">-params</span> 2 %{</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>  <span class="ex">set-option</span> <span class="at">-add</span> %arg{1} snippets_list %sh{ echo <span class="at">-e</span> <span class="st">&quot;</span><span class="va">$2</span><span class="st">\n&quot;</span> }</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="er">}</span></span></code></pre></div>
<div class="sourceCode" id="cb2"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ex">hook</span> global BufSetOption filetype=<span class="er">(</span><span class="ex">?:ruby</span><span class="kw">)</span> <span class="ex">%{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="ex">define-snippet</span> buffer snip-rails-class</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="er">}</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="ex">define-command</span> snip-rails-class %{</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  <span class="bu">eval</span> %sh{</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    <span class="va">class_name</span><span class="op">=</span><span class="va">$(</span><span class="fu">basename</span> <span class="st">&quot;</span><span class="va">$kak_bufname</span><span class="st">&quot;</span> .rb <span class="kw">|</span> <span class="fu">sed</span> <span class="at">-e</span> <span class="st">&#39;s/[^A-Za-z0-9]\(\w\)/\U\1/g&#39;</span> <span class="at">-e</span> <span class="st">&#39;s/^\w/\U\0/g&#39;</span><span class="va">)</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>    <span class="bu">echo</span> <span class="st">&quot;set-register c </span><span class="va">$class_name</span><span class="st">&quot;</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>  <span class="er">}</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>  <span class="ex">execute-keys</span> <span class="st">&#39;&lt;esc&gt;,i# frozen_string_literal: true&lt;ret&gt;&lt;ret&gt;&#39;</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>  <span class="ex">execute-keys</span> <span class="st">&#39;class &lt;c-r&gt;c&lt;ret&gt;&#39;</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>  <span class="ex">execute-keys</span> <span class="st">&#39;end&#39;</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a><span class="er">}</span></span></code></pre></div>
<p>Here, it parses the ruby class name from the file name to generate
the snippet but this could also just be a <code>prompt</code> command
instead.</p>
<p>This worked okay but it was pretty hard to maintain. Would be much
easier if the snippets themselves were easier to create and read. So,
that eventually evolved into this:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">declare-option</span> str snippets_dir <span class="st">&quot;%val{config}/snippets&quot;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ex">define-command</span> snippets-insert <span class="at">-docstring</span> <span class="st">&#39;Snippets&#39;</span> %{</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  <span class="ex">prompt</span> <span class="at">-menu</span> <span class="st">&quot;Snippets: &quot;</span> <span class="at">-init</span> <span class="st">&quot;%opt{filetype}/&quot;</span> <span class="dt">\</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    <span class="at">-shell-script-candidates</span> %{ fd <span class="at">--type</span> file <span class="at">--base-directory</span> <span class="st">&quot;</span><span class="va">$kak_opt_snippets_dir</span><span class="st">&quot;</span> } <span class="dt">\</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>     %{</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>      <span class="ex">evaluate-commands</span> %sh{</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>        <span class="cf">case</span> <span class="st">&quot;</span><span class="va">$kak_text</span><span class="st">&quot;</span> <span class="kw">in</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>          <span class="pp">*</span><span class="ss">.snip.kak</span><span class="kw">)</span> <span class="fu">cat</span> <span class="st">&quot;</span><span class="va">$kak_opt_snippets_dir</span><span class="st">/</span><span class="va">$kak_text</span><span class="st">&quot;</span> <span class="cf">;;</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>          <span class="pp">*</span><span class="kw">)</span> <span class="bu">echo</span> <span class="st">&quot;insert-text-snippet %{</span><span class="va">$kak_text</span><span class="st">}&quot;</span> <span class="cf">;;</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>        <span class="cf">esac</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>      <span class="er">}</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>    <span class="er">}</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a><span class="er">}</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a><span class="ex">define-command</span> <span class="at">-hidden</span> insert-text-snippet <span class="at">-params</span> 1 %{</span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a>  <span class="ex">execute-keys</span> <span class="st">&quot;,|cat &quot;&quot;%opt{snippets_dir}/%arg{1}&quot;&quot;&lt;ret&gt;&quot;</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a>  <span class="ex">execute-keys</span> <span class="at">-save-regs</span> <span class="st">&#39;&#39;</span> <span class="st">&quot;s[$]\d+&lt;ret&gt;&quot;</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a>  <span class="ex">execute-keys</span> <span class="st">&quot;%sh{echo </span><span class="va">$((kak_selection_count</span> <span class="op">+</span> <span class="dv">1</span><span class="va">))</span><span class="st">}n&quot;</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a><span class="er">}</span></span></code></pre></div>
<p>Now each snippet is a file placed in
<code>~/.config/kak/snippets/</code>. The files in my case are organized
by filetype in directories as <code>{filetype}/snippetname.{ext}</code>
or <code>{filetype}/snippetname.snip.kak</code>. The prompt is filled
with <code>{filetype}/</code> so at first you see the snippets for the
current filetype but you can delete that in the prompt to see all.</p>
<p>If it's a .snip.kak file, it is evaluated as a kakoune script which
is the same as the commands from before. Otherwise the contents of the
snippet file is inserted into the buffer directly and any
<code>$n</code> (<code>$1</code>, <code>$2</code>, ...) will be added as
a selection. Example:</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode ruby"><code class="sourceCode ruby"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="co"># frozen_string_literal: true</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="cf">class</span> <span class="va">$1</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">def</span> initialize</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    <span class="va">$2</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  <span class="cf">end</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>  <span class="va">$3</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="cf">end</span></span></code></pre></div>
<p>The above snippet, <code>$1</code> is automatically selected first.
You can press <code>c</code> to change it and <code>Esc</code> to go
back to normal mode. Then when you press <code>n</code>, it jumps to the
next <code>$n</code>.</p>
<p>I know this already exists for every other editor out of the box and
is much more fleshed out but the experience of understanding a system
and defining a feature within it, in it's simplest form, is a really
pleasant.</p>

]]>
</description></item>
<item><guid>2026-05-14-nixos-is-a-chore</guid>
<title>NixOS is a chore</title>
<link>https://ediblemonad.dev/tools/2026-05-14-nixos-is-a-chore</link>
<comments>https://ediblemonad.dev/tools/2026-05-14-nixos-is-a-chore</comments>
<pubDate>2026-05-14</pubDate>
<description>
<![CDATA[
<h1 id="nixos-is-a-chore">NixOS is a chore</h1>
<p>Using nixos is a chore like brushing your teeth. Oh... I mean "teeth
being brushed" (declarative).</p>
<p>It takes work. A big investment up front in configuring it and tiny
investments for as long as you use it to maintain the configuration.
Sounds like a scam but I thank myself for this investment every time
there is a bad update or running a project with a flake and having it
work fine after many years of sitting idle (which is suprising in the
modern norm of having a web of dependencies). This brings an insane
amount of confidence in any change I make to my system which lets me
explore more things without being afraid touching the wrong thing on MY
computer.</p>
<p>I've had it running as a daily driver for about 6 years and on my
home server (just an old laptop) for more than a year. My review: 10/10,
do it.</p>
<div style="text-align:center;">
  <img src="/images/nixos.png" alt="NixOS declarative" style="width:100%;max-width:400px" />
</div>

]]>
</description></item>
<item><guid>2026-05-03-kakoune-supremacy</guid>
<title>Kakoune supremacy</title>
<link>https://ediblemonad.dev/tools/2026-05-03-kakoune-supremacy</link>
<comments>https://ediblemonad.dev/tools/2026-05-03-kakoune-supremacy</comments>
<pubDate>2026-05-03</pubDate>
<description>
<![CDATA[
<h1 id="kakoune-supremacy">Kakoune supremacy</h1>
<p>I've tried a bunch of different code editors and IDEs over the years
but nothing beats the control of a modal text editor. Even as "vi
plugins" in normie editors and IDEs, the difference in user experience
is massive. But I've come to crave more from my tools. By "more" I mean
fewer features and better primitives to allow me to build my own
experience on top of it. Because at the end of the day, I've spend a
considerable amount of time using the tools that I use for work and as a
hobby so I know better than the devs of these tools what I'd like my
tool to do.</p>
<p>For a while my answer to this was neovim (vim before that). Neovim is
a really solid code editor and it comes with the simplest and a really
powerful configuration framework for building on top of it (emacs guys
suck it (jk, I love emacs too)). I dove so deep into the lua rabit-hole
that I trimmed my setup down to a few essential plugins and every other
feature was implemented by me in my config. But over time, I've felt
like the foundations are a bit "off". The primitives that it provides
felt a bit inconsistent and like carrying too much weight for my
taste.</p>
<p>So as any mentally ill person would, I decided to spend a shit-load
of time setting up a kakoune configuration that I could use many moons
ago. And it just made sense. Kakoune's shell based extension framework
is exactly the kind of simplicity that I was looking for. It is in no
way a perfect editor but it fits in my hands perfectly. No file
explorer, no build system, no fancy built-in language server, no split
windows, etc. Nothing other than a simple code editor with a good-enough
configuration language that lets you integrate kakoune with any other
tool you want. I have unix blood in my veins. This kind of workflow
turns my terminal into an IDE with the editor just being a part of it
(instead of the other way around. Looking at you, emacs). I still love
neovim and might go back to it in the future but kakoune feels right for
now.</p>
<p>My crotch has never been wetter. Kthanxby.</p>

]]>
</description></item>
<item><guid>2026-09-04-differential-pair-skew-check-in-kicad</guid>
<title>Differential pair skew check in kicad</title>
<link>https://ediblemonad.dev/hardware/2026-09-04-differential-pair-skew-check-in-kicad</link>
<comments>https://ediblemonad.dev/hardware/2026-09-04-differential-pair-skew-check-in-kicad</comments>
<pubDate>2026-09-04</pubDate>
<description>
<![CDATA[
<h1 id="differential-pair-skew-check-in-kicad">Differential pair skew
check in kicad</h1>
<p>Love DRC. Can't live without it. Want more. But there's some things
that DRC doesn't know how to do out of the box like verifying the skew
in my differential pair traces or telling me I'm a good boy. Luckily
custom rules makes up for it (at least the first part)!</p>
<p>Go to Board Setup &gt; Design Rules &gt; Custom Rules (or manually
edit <code>*.kicad_dru</code> file, if you're not right in the head) and
add the following:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode lisp"><code class="sourceCode commonlisp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>(version <span class="dv">1</span>)</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>(rule <span class="st">&quot;100Ohm differential pair skew&quot;</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    (<span class="kw">condition</span> <span class="st">&quot;A.NetClass == &#39;100Ohm&#39;&quot;</span>)</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    (constraint skew (<span class="kw">max</span> <span class="fl">0.05</span>mm) (within_diff_pairs)))</span></code></pre></div>
<p>The above rule is specifically for a net class named
<code>100Ohm</code>. This will show up as an error if your differential
pairs have a skew greater than 0.05mm. You can also use
<code>A.hasNetclass('DiffPair-*')</code> if you have some
<code>DiffPair-100Ohm</code>, <code>DiffPair-90Ohm</code>, etc.
convention going on. Or combine them as
<code>(condition "A.hasNetclass('100Ohm') || A.hasNetclass('90Ohm')")</code></p>
<p>There's a bunch of other constraints you can check for like
diff_pair_uncoupled, diff_pair_gap, track_width, etc. Check the "Syntax
Help" thing in the modal to see more stuff it comes with.</p>

]]>
</description></item>
<item><guid>2026-05-23-learnings-from-sinthinator</guid>
<title>Learnings from sinthinator</title>
<link>https://ediblemonad.dev/hardware/2026-05-23-learnings-from-sinthinator</link>
<comments>https://ediblemonad.dev/hardware/2026-05-23-learnings-from-sinthinator</comments>
<pubDate>2026-05-23</pubDate>
<description>
<![CDATA[
<h1 id="learnings-from-sinthinator">Learnings from sinthinator</h1>
<p>I recently tried decided to randomly pick up a pcb design project for
an
<a target="_blank _parent" rel="noopener" href="https://github.com/phenax/sinthinator">stm32
based toy music instrument</a> that used capacitive touch sensor traces
on a PCB. Expected it to be a bit of a challenge because I've never
dealt with most of the components involved and only have basic
experience with SMD components.</p>
<p>Stuff I've learned:</p>
<ul>
<li>keep in mind ICs with identical i2c addresses when you have multiple
devices on an i2c bus. Use separate busses if possible or i2c
multiplexer if thats becoming a problem</li>
<li>dont forget the cc pins on a usbc connector</li>
<li>read the datasheet more carefully and dont just rely on the "typical
application" diagram</li>
<li>keep pcb traces in mind when drawing schematics. Not to have them
laid out the same way, but whenever there's a choice for which pins keep
the ICs position in mind. Or just re-do the connections in the
schematics later, I'm not your dad</li>
<li>add extra header pins/test pads to make debugging easier. Always
design for testing.</li>
<li>use solder jumpers and DNP resistors as "flags" if needed</li>
<li>add the mounting holes as soon as possible after board outline to
reserve enough space for them</li>
<li>for mcus, plan the firmware early on when drawing out the
schematics</li>
<li>pay attention to res pullups values for i2c lines based on the
frequency (from i2c spec). Used 4.7K on mine which seems alright</li>
<li>dont move the ic around in the pcb and leave the bypass capacitors
behind (happened twice)</li>
</ul>
<p>project is wip so will add more here as a fuck more things up...</p>

]]>
</description></item>
<item><guid>2026-05-14-need-at-least-2-uarts</guid>
<title>Single UART? More like U-fart. JK haha lol</title>
<link>https://ediblemonad.dev/hardware/2026-05-14-need-at-least-2-uarts</link>
<comments>https://ediblemonad.dev/hardware/2026-05-14-need-at-least-2-uarts</comments>
<pubDate>2026-05-14</pubDate>
<description>
<![CDATA[
<h1 id="single-uart-more-like-u-fart-jk-haha-lol">Single UART? More like
U-fart. JK haha lol</h1>
<p>I think people who make SBCs should add at least 2 UART ports. RPI
zero just has 1 which hurts when you want to reserve the UART port for
serial console and then all of a sudden you also need it to communicate
with some other module. I'm in that situation right now.</p>
<p>Options I have:</p>
<ol type="1">
<li>USB for console with dwc2 (depends on SBC). UART for module.</li>
<li>UART for serial console. USB-to-serial adapter for module (or
vice-versa but makes more sense if console's serial device can't be
unplugged).</li>
<li>UART for serial console. Bit-bang the module at a much lower baud
rate (if that's supported).</li>
<li>Board has wifi? Just ssh into it. Although, seems overkill for
simpler use-cases and might not be ideal in some situations. Not an
option for my pi zero.</li>
</ol>
<p>Maybe theres another option that I'm not aware of?</p>
<p>Going with 1 because it's less work on a pi zero. USB-to-serial if
the board doesn't support dwc2. But for a serial console you have to 69
2 USB-to-serial adapters to get a console. But all of this goes away if
you just fucking add the 2nd UART port.</p>

]]>
</description></item>
<item><guid>2026-04-29-fpga-dreams</guid>
<title>FPGA dreams</title>
<link>https://ediblemonad.dev/hardware/2026-04-29-fpga-dreams</link>
<comments>https://ediblemonad.dev/hardware/2026-04-29-fpga-dreams</comments>
<pubDate>2026-04-29</pubDate>
<description>
<![CDATA[
<h1 id="fpga-dreams">FPGA dreams</h1>
<p>I want to mess around with FPGAs at some point. It looks really
interesting but I need to grow a few more IQ points before I can play
with that new toy. At this point I know nothing about them or hardware
description languages but can't wait to meet future me who already knows
some of that stuff. If that's you reading this for some reason, is GTA 6
out yet?</p>

]]>
</description></item>
<item><guid>2026-04-12-v-usb-is-kinda-neat</guid>
<title>V-USB is kinda neat</title>
<link>https://ediblemonad.dev/hardware/2026-04-12-v-usb-is-kinda-neat</link>
<comments>https://ediblemonad.dev/hardware/2026-04-12-v-usb-is-kinda-neat</comments>
<pubDate>2026-04-12</pubDate>
<description>
<![CDATA[
<h1 id="v-usb-is-kinda-neat">V-USB is kinda neat</h1>
<p>I only ran into
<a target="_blank _parent" rel="noopener" href="https://github.com/obdev/v-usb">v-usb</a>
while going through the
<a target="_blank _parent" rel="noopener" href="https://docs.qmk.fm/compatible_microcontrollers">qmk
docs</a> where it mentions that mcus that don't have native usb will use
v-usb instead.</p>
<p>Curiosity killed the akshay. Couldn't resist so started thinking of
what I could use it for. Right now I'm in my 8-bit avr arc so seemed
like the perfect thing to mess around with. I thought it would be fun to
make a simple rgb light connected via USB that changes color via
commands over serial. Seems simple enough, what could go wrong? Plenty
as it turns out.</p>
<p>First challenge: realized the internal clock of attiny84a and
attiny4313 (the only 8-bit avr mcus I have) is 8MHz and v-usb only
supports 12/15/16/18/20 MHz clocks. No biggie, heres a 16MHz crystal
oscillator.</p>
<p>Second challenge: we need 3.3V for the usb data lines but the LEDs
need 5V. I can either drive the attiny4313 with 3.3V and maybe add a
mosfet for the LEDs or use 5V for the mcu and LED but shift D+/D- to
3.3V level. Went with the latter using a zener diode to maintain the
3.3V level on data lines since that seemed simpler.</p>
<p>Third challenge: after writing the fuse bits to use the external
crystal oscillator, couldn't program it again. The crystal is connected
with load caps and the program (an rgb version of blink) seems to run
fine with or without the crystal. Makes no sense. Saw somewhere that you
can set up a high voltage programmer (12v) to get the fuse bits to
reset. So will try that next.</p>
<p>To be continued...</p>

]]>
</description></item>
<item><guid>2026-03-08-analog-of-digital</guid>
<title>The analog of the digital</title>
<link>https://ediblemonad.dev/hardware/2026-03-08-analog-of-digital</link>
<comments>https://ediblemonad.dev/hardware/2026-03-08-analog-of-digital</comments>
<pubDate>2026-03-08</pubDate>
<description>
<![CDATA[
<h1 id="the-analog-of-the-digital">The analog of the digital</h1>
<p>In digital electronics something that always catches me off guard is
the analog suprise. Don't get me started on signal integrity issues but
what I'm talking about is when a random part of your schematic depends
on a very specific analog behavior. I ran into one of those while
working on
<a target="_blank _parent" rel="noopener" href="https://github.com/makedaft/daft-watch">a
clock using attiny84a microcontroller IC</a>. That project was my
re-creation of
<a target="_blank _parent" rel="noopener" href="https://ingep.net/breadboardwatch/">breadboard
watch</a> which taught me a very simple but neat trick.</p>
<p>An rtc based on timer interrupts on a microcontroller, displayed on a
4 digit, 7 segment display seems simple enough but theres a sneaky
problem with attiny84a. The total number of pins in the IC is 14. 1 for
Vcc, 1 for GND, 1 for reset. Since it's battery powered, to avoid
drawing more power than needed, we also need to use an external 32KHz
crystal oscillator which then takes up the 2 XTAL pins. This leaves us
with 9 pins to drive the display. But for 4 7-segment displays, you need
1 shared pin for each segments and 1 control pin for each digit. That
comes out to 11 (7 + 4). But we only have 9 pins left so how do we drive
the display?</p>
<p>In avr, for a given pin, you can set the data direction (DDR*
register) and the port value (PORT* register). When DDR bit is 1, the
data direction is output so the respective PORT bit decides whether the
output is high or low. But then if the DDR bit is 0, the value of PORT
instead of being used for the output of that pin, it engages an internal
pull-up resistor if the value is 1, and leaves it floating if the value
is 0.</p>
<p>This is the magic that makes feel things in the crotch. The solution
used here is to use diodes to create a sort-of OR circuit by deriving
segment states based on the state of the control pins. Here's the
<a target="_blank _parent" rel="noopener" href="https://raw.githubusercontent.com/makedaft/daft-watch/refs/heads/main/watch.svg">full
schematic for reference</a>.</p>
<blockquote>
<p>Note: in my case it's a common anode display so segment pin low and
control pin high means that segment on that digit is on.</p>
</blockquote>
<p>In the schematic, with
<code>DDRA = (1 &lt;&lt; PA6) | (1 &lt;&lt; PA7)</code> (PA6 and PA7
both output),</p>
<ul>
<li>When PA6 is high, and PA7 is low, it enables digit 3 and the F
segment.</li>
<li>When PA6 is low, and PA7 is high, it enables digit 4 and the F
segment.</li>
</ul>
<p>If we have <code>DDRA = 0</code> (PA6,PA7 both input),</p>
<ul>
<li>When <code>PORTA = 0</code> (PA6,PA7 without internal pullup
resistor), being floating, there is no current flowing which means both
digits are off and the F segment is off. This state can be used when
drawing the other 2 digits.</li>
</ul>
<p>So far we can turn off both digits or have either one on but with F
segment enabled. But how do we disable the F segment?</p>
<p>If we have <code>DDRA = (1 &lt;&lt; PA6)</code> (PA6 output, PA7
input),</p>
<ul>
<li>When <code>PORTA = (1 &lt;&lt; PA6)</code> (PA6 high, PA7 floating),
digit 3 is on but the F segment is off as the current has nowhere to go
through the diodes.</li>
</ul>
<p>Applying the inverse of that, we can achieve the last state we need
to draw anything on each of the 7 segment displays. With this we now
have 2 pins doing the work for 3. Adding in-between states in our
digital logic that don't exist in pure boolean logic. Doesn't that feel
satisfying?</p>

]]>
</description></item>
<item><guid>kaleidoblot</guid>
<title>Kaleidoblot</title>
<link>https://ediblemonad.dev/creative-coding/kaleidoblot</link>
<comments>https://ediblemonad.dev/creative-coding/kaleidoblot</comments>

<description>
<![CDATA[
<h1 id="kaleidoblot">Kaleidoblot</h1>
<div class="image-container"><video src="/cc/kaleidoblot.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/resources/shaders/kaleidos.glsl">code</a></p>
<p>I see a butterfly... turning into another butterfly... turning into
another butterfly... turning into... eh I'm bored.</p>

]]>
</description></item>
<item><guid>cross</guid>
<title>Cross</title>
<link>https://ediblemonad.dev/creative-coding/cross</link>
<comments>https://ediblemonad.dev/creative-coding/cross</comments>

<description>
<![CDATA[
<h1 id="cross">Cross</h1>
<div class="image-container"><video src="/cc/cross.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/kotlin/blood/BloodProgram.kt">code</a></p>

]]>
</description></item>
<item><guid>icecream-sandwich</guid>
<title>Ice cream sandwich</title>
<link>https://ediblemonad.dev/creative-coding/icecream-sandwich</link>
<comments>https://ediblemonad.dev/creative-coding/icecream-sandwich</comments>

<description>
<![CDATA[
<h1 id="ice-cream-sandwich">Ice cream sandwich</h1>
<div class="image-container"><video src="/cc/icecream-sandwich.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/resources/shaders/icecream.glsl">code</a></p>
<p>I like ice cream sandwich. A lot more when I stop liking everything
else.</p>

]]>
</description></item>
<item><guid>time</guid>
<title>Time</title>
<link>https://ediblemonad.dev/creative-coding/time</link>
<comments>https://ediblemonad.dev/creative-coding/time</comments>

<description>
<![CDATA[
<h1 id="time">Time</h1>
<div class="image-container"><video src="/cc/time.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/resources/shaders/time.glsl">code</a></p>
<p>I don't like eyeballs</p>

]]>
</description></item>
<item><guid>evolution</guid>
<title>Evolution</title>
<link>https://ediblemonad.dev/creative-coding/evolution</link>
<comments>https://ediblemonad.dev/creative-coding/evolution</comments>

<description>
<![CDATA[
<h1 id="evolution">Evolution</h1>
<div class="image-container"><a target="_blank _parent" rel="noopener" href="/cc/flow/flow.FlowProgram.eye.png"><img src="/cc/flow/flow.FlowProgram.eye.png" alt="Evolution" loading="lazy"></img></a></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/kotlin/flow/FlowProgram.kt">code</a></p>
<p>Order from chaos</p>

]]>
</description></item>
<item><guid>koduval</guid>
<title>Koduval</title>
<link>https://ediblemonad.dev/creative-coding/koduval</link>
<comments>https://ediblemonad.dev/creative-coding/koduval</comments>

<description>
<![CDATA[
<h1 id="koduval">Koduval</h1>
<div class="image-container"><a target="_blank _parent" rel="noopener" href="/cc/koduval.png"><img src="/cc/koduval.png" alt="Koduval" loading="lazy"></img></a></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/resources/shaders/koduval.glsl">code</a></p>
<p>Koduval is a tool used for cutting open coconuts (among other things)
in south India.</p>

]]>
</description></item>
<item><guid>flow</guid>
<title>Flow (collection)</title>
<link>https://ediblemonad.dev/creative-coding/flow</link>
<comments>https://ediblemonad.dev/creative-coding/flow</comments>

<description>
<![CDATA[
<h1 id="flow-collection">Flow (collection)</h1>
<div class="img-table">
  <div><h4>Flames</h4><div class="image-container"><a target="_blank _parent" rel="noopener" href="/cc/flow/flow.FlowProgram.flames.png"><img src="/cc/flow/flow.FlowProgram.flames.png" alt="Flames" loading="lazy"></img></a></div></div>
  <div><h4>Glide</h4><div class="image-container"><a target="_blank _parent" rel="noopener" href="/cc/flow/flow.FlowProgram.gentle.png"><img src="/cc/flow/flow.FlowProgram.gentle.png" alt="Glide" loading="lazy"></img></a></div></div>

  <div><h4>Now and then</h4><div class="image-container"><a target="_blank _parent" rel="noopener" href="/cc/flow/flow.FlowProgram.nowandthen.png"><img src="/cc/flow/flow.FlowProgram.nowandthen.png" alt="Now and then" loading="lazy"></img></a></div></div>
  <div><h4>Stuck in beetween</h4><div class="image-container"><a target="_blank _parent" rel="noopener" href="/cc/flow/flow.FlowProgram.stuckinbetween.png"><img src="/cc/flow/flow.FlowProgram.stuckinbetween.png" alt="Stuck in between" loading="lazy"></img></a></div></div>
  <div><h4>Doorway</h4><div class="image-container"><a target="_blank _parent" rel="noopener" href="/cc/flow/flow.FlowProgram.hollow.png"><img src="/cc/flow/flow.FlowProgram.hollow.png" alt="Doorway" loading="lazy"></img></a></div></div>
  <div><h4>Fibers</h4><div class="image-container"><a target="_blank _parent" rel="noopener" href="/cc/flow/flow.FlowProgram.flow.png"><img src="/cc/flow/flow.FlowProgram.flow.png" alt="Fibers" loading="lazy"></img></a></div></div>

</div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/kotlin/flow/FlowProgram.kt">code</a></p>
<p>All about the flo, bro</p>

]]>
</description></item>
<item><guid>placenta</guid>
<title>Placenta</title>
<link>https://ediblemonad.dev/creative-coding/placenta</link>
<comments>https://ediblemonad.dev/creative-coding/placenta</comments>

<description>
<![CDATA[
<h1 id="placenta">Placenta</h1>
<div class="image-container"><a target="_blank _parent" rel="noopener" href="/cc/placenta.png"><img src="/cc/placenta.png" alt="Placenta" loading="lazy"></img></a></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/resources/shaders/placenta.glsl">code</a></p>
<p>Placenta is an organ that develops in the uterus during pregnancy to
connect the mother and the developing fetus.</p>

]]>
</description></item>
<item><guid>adopted-moth</guid>
<title>Adopted moth</title>
<link>https://ediblemonad.dev/creative-coding/adopted-moth</link>
<comments>https://ediblemonad.dev/creative-coding/adopted-moth</comments>

<description>
<![CDATA[
<h1 id="adopted-moth">Adopted moth</h1>
<div class="image-container"><a target="_blank _parent" rel="noopener" href="/cc/adopted-moth.png"><img src="/cc/adopted-moth.png" alt="Adopted moth" loading="lazy"></img></a></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/resources/shaders/trtrfr.glsl">code</a></p>
<p><a target="_blank _parent" rel="noopener" href="/cc/adopted-moth.4k.png">4K
version</a> <br /></p>
<p>Fun fact: moths fly towards light because night-night really
scary</p>

]]>
</description></item>
<item><guid>blood</guid>
<title>Blood (collection)</title>
<link>https://ediblemonad.dev/creative-coding/blood</link>
<comments>https://ediblemonad.dev/creative-coding/blood</comments>

<description>
<![CDATA[
<h1 id="blood-collection">Blood (collection)</h1>
  <div class="img-table">
    <div><h4>Coral</h4><div class="image-container"><video src="/cc/blood/blood.BloodProgram.coral.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div></div>
    <div><h4>Mitosis</h4><div class="image-container"><video src="/cc/blood/blood.BloodProgram.mitosis.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div></div>
    <div><h4>Waves</h4><div class="image-container"><video src="/cc/blood/blood.BloodProgram.waves.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div></div>
    <div><h4>Rangoli</h4><div class="image-container"><video src="/cc/blood/blood.BloodProgram.pulseSettled1.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div></div>
    <div><h4>Worms</h4><div class="image-container"><video src="/cc/blood/blood.BloodProgram.worms.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div></div>
    <div><h4>Popping bubbles</h4><div class="image-container"><video src="/cc/blood/blood.BloodProgram.bubbles.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div></div>
    <div><h4>Cross</h4><div class="image-container"><video src="/cc/blood/blood.BloodProgram.pulseSettled2.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div></div>
    <div><h4>Holes</h4><div class="image-container"><video src="/cc/blood/blood.BloodProgram.holey.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div></div>
    <div><h4>Explosions</h4><div class="image-container"><video src="/cc/blood/blood.BloodProgram.explosions.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div></div>
  </div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/kotlin/blood/BloodProgram.kt">code</a></p>

]]>
</description></item>
<item><guid>vase</guid>
<title>Vase</title>
<link>https://ediblemonad.dev/creative-coding/vase</link>
<comments>https://ediblemonad.dev/creative-coding/vase</comments>

<description>
<![CDATA[
<h1 id="vase">Vase</h1>
<div class="image-container"><a target="_blank _parent" rel="noopener" href="/cc/vase.png"><img src="/cc/vase.png" alt="Vase" loading="lazy"></img></a></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/resources/shaders/vase.glsl">code</a></p>

]]>
</description></item>
<item><guid>newton</guid>
<title>Newton</title>
<link>https://ediblemonad.dev/creative-coding/newton</link>
<comments>https://ediblemonad.dev/creative-coding/newton</comments>

<description>
<![CDATA[
<h1 id="newton">Newton</h1>
<div class="image-container"><video src="/cc/newton.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/resources/shaders/newton.glsl">code</a></p>

]]>
</description></item>
<item><guid>cloak</guid>
<title>Cloak</title>
<link>https://ediblemonad.dev/creative-coding/cloak</link>
<comments>https://ediblemonad.dev/creative-coding/cloak</comments>

<description>
<![CDATA[
<h1 id="cloak">Cloak</h1>
<div class="image-container"><a target="_blank _parent" rel="noopener" href="/cc/cloak.png"><img src="/cc/cloak.png" alt="Cloak" loading="lazy"></img></a></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/resources/shaders/cloak.glsl">code</a></p>
<p>He's not wearing anything under that</p>

]]>
</description></item>
<item><guid>geography</guid>
<title>Geography</title>
<link>https://ediblemonad.dev/creative-coding/geography</link>
<comments>https://ediblemonad.dev/creative-coding/geography</comments>

<description>
<![CDATA[
<h1 id="geography">Geography</h1>
<div class="image-container"><video src="/cc/geography.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/resources/shaders/warping.glsl">code</a></p>

]]>
</description></item>
<item><guid>mitosis</guid>
<title>Mitosis</title>
<link>https://ediblemonad.dev/creative-coding/mitosis</link>
<comments>https://ediblemonad.dev/creative-coding/mitosis</comments>

<description>
<![CDATA[
<h1 id="mitosis">Mitosis</h1>
<div class="image-container"><video src="/cc/mitosis.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/resources/shaders/mitosis.glsl">code</a>
<br />
<a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/uiua-creative-coding/tree/4-im-a-sinner/main.ua">older
uiua version</a></p>

]]>
</description></item>
<item><guid>hope</guid>
<title>Hope</title>
<link>https://ediblemonad.dev/creative-coding/hope</link>
<comments>https://ediblemonad.dev/creative-coding/hope</comments>

<description>
<![CDATA[
<h1 id="hope">Hope</h1>
<div class="image-container"><audio src="/cc/hope.mp3" controls="true"></audio></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/uiua-creative-coding/tree/5-polyrhythms/main.ua">code</a></p>

]]>
</description></item>
<item><guid>recursticks</guid>
<title>Recursticks</title>
<link>https://ediblemonad.dev/creative-coding/recursticks</link>
<comments>https://ediblemonad.dev/creative-coding/recursticks</comments>

<description>
<![CDATA[
<h1 id="recursticks">Recursticks</h1>
<div class="image-container"><a target="_blank _parent" rel="noopener" href="/cc/recursticks.jpg"><img src="/cc/recursticks.jpg" alt="Recursticks" loading="lazy"></img></a></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/creative-coding-playground/tree/sketches/08/tree.rkt">code</a></p>

]]>
</description></item>
<item><guid>vacation</guid>
<title>Vacation</title>
<link>https://ediblemonad.dev/creative-coding/vacation</link>
<comments>https://ediblemonad.dev/creative-coding/vacation</comments>

<description>
<![CDATA[
<h1 id="vacation">Vacation</h1>
<div class="image-container"><a target="_blank _parent" rel="noopener" href="/cc/vacation.png"><img src="/cc/vacation.png" alt="Vacation" loading="lazy"></img></a></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/resources/shaders/vacation.glsl">code</a></p>

]]>
</description></item>
<item><guid>seigaiha</guid>
<title>Seigaiha</title>
<link>https://ediblemonad.dev/creative-coding/seigaiha</link>
<comments>https://ediblemonad.dev/creative-coding/seigaiha</comments>

<description>
<![CDATA[
<h1 id="seigaiha">Seigaiha</h1>
<div class="image-container"><video src="/cc/seigaiha.mp4" loading="lazy" preload="none" controls="true" autoplay="autoplay" muted="true" loop="loop"></video></div>

<p><a target="_blank _parent" rel="noopener" href="https://git.ediblemonad.dev/art-playground-openrndr/tree/src/main/resources/shaders/seigaiha.glsl">code</a></p>

]]>
</description></item>
<item><guid>2026-10-09-coding-is-a-niche-hobby-again</guid>
<title>Coding is a niche hobby again!</title>
<link>https://ediblemonad.dev/coding4fun/2026-10-09-coding-is-a-niche-hobby-again</link>
<comments>https://ediblemonad.dev/coding4fun/2026-10-09-coding-is-a-niche-hobby-again</comments>
<pubDate>2026-10-09</pubDate>
<description>
<![CDATA[
<h1 id="coding-is-a-niche-hobby-again">Coding is a niche hobby
again!</h1>
<p>For a while programming was one of the most lucrative career options
for someone to pick. Still is to some extent. But there was a time
before all of this when computers weren't everywhere as they are now and
majority of programmers were just nerds with a niche hobby.</p>
<p>With the whole AI takeover of the industry, the value of code has
gone all the way down. A lot of people have lost interest in writing
code by themselves. The value of code is as low as it was back then and
writing code is not really a job anymore. We've come full circle.</p>
<p>This at first made me feel sad about the state of things. Mainly
because of the huge discrepency between how I feel about coding and how
the world does now. But that feeling was short-lived because as it turns
out, I still feel the same way about code as I did when I first started.
It's still as satisfying and enjoyable as the first "hello world". Yeah
most of the software industry now uses AI to produce code, but thats
alright. I can still write my own code in my free time and I still love
doing it!</p>
<p>There's so much depth to programming, so many rabit holes to dive
into and so much more to learn that coding as a hobby will stay fun for
me for the foreseeable future. I won't be using AI for any of the code I
write for fun because I don't care about producing hobby code faster. I
wouldn't use an ice-cream eating robot to eat my ice-cream for me just
because it can do it faster or better.</p>
<p>So yeah, coding's just a niche hobby again. And it's a really fun
one!</p>

]]>
</description></item>
<item><guid>2026-06-27-polar-coordinates-are-beautiful</guid>
<title>Polar coordinates are beautiful</title>
<link>https://ediblemonad.dev/coding4fun/2026-06-27-polar-coordinates-are-beautiful</link>
<comments>https://ediblemonad.dev/coding4fun/2026-06-27-polar-coordinates-are-beautiful</comments>
<pubDate>2026-06-27</pubDate>
<description>
<![CDATA[
<h1 id="polar-coordinates-are-beautiful">Polar coordinates are
beautiful</h1>
<p>Just go over to
<a target="_blank _parent" rel="noopener" href="https://www.desmos.com/calculator">desmos</a>
and type a random equation with polar coordinates. There is a very good
chance, you see something visually interesting.</p>
<p>Examples (try with <span
class="math inline">−12<em>π</em> ≤ <em>θ</em> ≤ 12<em>π</em></span>):</p>
<ul>
<li><span class="math inline"><em>r</em> = <em>θ</em></span>: the
simplest form is already a spiral</li>
<li><span
class="math inline"><em>r</em> = <em>θ</em><sup>2</sup></span>: sqaure
it, something that looks like infinite hear shapes</li>
<li><span
class="math inline"><em>r</em> = <em>e</em><sup><em>θ</em></sup></span>:
try zooming into it, it goes on forever</li>
<li><span class="math inline"><em>r</em> = sin (0.3<em>θ</em>)</span>:
some floral shape. mess around with the factor (0.3) to watch it unravel
in really cool ways.</li>
<li><span
class="math inline"><em>r</em> = <em>e</em><sup><em>θ</em>(sin (<em>θ</em>)cos (<em>θ</em>))<sup>6</sup></sup></span>:
would make a really cool visualizer for music</li>
</ul>
<p>Designing a logo? Just play around with polar coordinates till you
find a shape inside it that looks interesting. Won't take long.</p>

]]>
</description></item>
<item><guid>2026-06-03-creative-coding-in-sqlite</guid>
<title>Creative coding in sqlite</title>
<link>https://ediblemonad.dev/coding4fun/2026-06-03-creative-coding-in-sqlite</link>
<comments>https://ediblemonad.dev/coding4fun/2026-06-03-creative-coding-in-sqlite</comments>
<pubDate>2026-06-03</pubDate>
<description>
<![CDATA[
<h1 id="creative-coding-in-sqlite">Creative coding in sqlite</h1>
<p>Been trying out creative coding in sqlite recently
<a target="_blank _parent" rel="noopener" href="https://github.com/phenax/sqlite-creative-coding">here</a>.
Turned out to be a lot more fun than what writing practical SQL had
conditioned me to believe!</p>
<p>Generating images is pretty straight forward. The SQL uses
<a target="_blank _parent" rel="noopener" href="https://sqlite.org/lang_with.html">recursive
CTE</a> to generate and store pixel rgb values in the db. Then a bash
script reads the pixel values structures them in the ppm text format
which is then converted to png using imagemagick. I was thinking of
taking this a step further by converting to ppm from within sql but
didn't feel like that added much except boilerplate.</p>
<p>Currently I've got 2 scripts image.sh and video.sh to generate images
and videos respectively.</p>
<ul>
<li><strong>image.sh</strong>: Generates a ppm from the pixels stored in
the db. Uses imagemagick to convert that to a png (and also for
displaying it)</li>
<li><strong>video.sh</strong>: Generates a ppm stream for each stored
frame of the video. Uses ffmpeg to convert that to a gif (and uses
ffplay for displaying it)</li>
</ul>
<p>Here's a simplified example that generates 400x400 grid of pixels
with a circle in the middle:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode sql"><code class="sourceCode sql"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">WITH</span> RECURSIVE</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    image(width, height, cx, cy, radius) <span class="kw">AS</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>        (<span class="kw">SELECT</span> <span class="dv">400</span> <span class="kw">AS</span> width, <span class="dv">400</span> <span class="kw">AS</span> height, <span class="dv">200</span> <span class="kw">AS</span> cx, <span class="dv">200</span> <span class="kw">AS</span> cy, <span class="dv">160</span> <span class="kw">AS</span> radius),</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    horizontal(x) <span class="kw">AS</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>        (<span class="kw">SELECT</span> width <span class="kw">FROM</span> image</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>            <span class="kw">UNION</span> <span class="kw">ALL</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>            <span class="kw">SELECT</span> x <span class="op">-</span> <span class="dv">1</span> <span class="kw">FROM</span> horizontal <span class="kw">WHERE</span> x <span class="op">&gt;</span> <span class="dv">1</span>),</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    vertical(y) <span class="kw">AS</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>        (<span class="kw">SELECT</span> height <span class="kw">FROM</span> image</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>            <span class="kw">UNION</span> <span class="kw">ALL</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>            <span class="kw">SELECT</span> y <span class="op">-</span> <span class="dv">1</span> <span class="kw">FROM</span> vertical <span class="kw">WHERE</span> y <span class="op">&gt;</span> <span class="dv">1</span>)</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span> x, y,</span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>    <span class="dv">255</span> <span class="op">*</span> <span class="fu">MAX</span>(<span class="dv">0</span>, <span class="fu">MIN</span>(<span class="dv">1</span>, (x <span class="op">-</span> cx)<span class="op">*</span>(x <span class="op">-</span> cx) <span class="op">+</span> (y <span class="op">-</span> cy)<span class="op">*</span>(y <span class="op">-</span> cy) <span class="op">-</span> radius<span class="op">*</span>radius)),</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>    <span class="dv">150</span>,</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>    <span class="dv">150</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>    <span class="kw">FROM</span> vertical, horizontal, image;</span></code></pre></div>
<p>Here, <code>horizontal</code>/<code>vertical</code> generates x and y
coordinates, the final select assigns the r,g,b values for each x,y
coordinate which is what allows generating the visuals.</p>
<p>In the repo, I'm storing the pixels instead of generating just
generating them directly. I went with this approach for 2 reasons -
debugging and reducing the pain of generating a video. Although,
could've used materialized views but nah simpler is better.</p>
<p>Generating audio out of samples should also be simple with raw PCM
data and then to ffmpeg to convert to wav but haven't tried that yet.
Another more ambitious idea is to build a simple snake game. The way I'm
thinking is with the ppm output streaming to ffplay and using terminal
raw mode for input which will update relevant values either directly or
via triggers. Leaving that for future me to fuck around with.</p>
<p>SQL can be fun.</p>

]]>
</description></item>
<item><guid>2026-03-24-desmos</guid>
<title>Desmos is beautiful</title>
<link>https://ediblemonad.dev/coding4fun/2026-03-24-desmos</link>
<comments>https://ediblemonad.dev/coding4fun/2026-03-24-desmos</comments>
<pubDate>2026-03-24</pubDate>
<description>
<![CDATA[
<h1 id="desmos-is-beautiful">Desmos is beautiful</h1>
<p>Desmos is a graphing calculator where you can input math equations
and it'll plot it. The normal way to use it would be to throw in an
equation like <span
class="math inline"><em>y</em> = 2<em>x</em><sup>2</sup> + 2</span> and
boom you have a parabola. Even though it might seem simple on the
surface, it is hiding an incredible programming language and rendering
engine that you can use to build pretty much anything you'd like.</p>
<p>Want to draw a box and a circle? <span
class="math display">{−5 &lt; <em>x</em> &lt; 5}{−5 &lt; <em>y</em> &lt; 5} &gt; 0</span>
<span
class="math display"><em>x</em><sup>2</sup> + <em>y</em><sup>2</sup> &lt; 25</span></p>
<p>Here, the comparisons at the top level means region (or range in
general) and conditional enclosed in curly braves like <span
class="math inline">{−5 &lt; <em>x</em> &lt; 5 &gt; 0}</span> are
expressions that can either return 1 if true or undefined if false. 2 of
these expressions next to each other is the product of both.</p>
<p>Want to conditionally draw either a box or a circle and toggle
between them on the click of a button?
(<a target="_blank _parent" rel="noopener" href="https://www.desmos.com/calculator/zom3hguvjv">on
desmos</a>) <span
class="math display">{<em>V</em><sub><em>i</em><em>s</em><em>c</em><em>i</em><em>r</em><em>c</em><em>l</em><em>e</em></sub> = 1 : −<em>x</em><sup>2</sup> − <em>y</em><sup>2</sup> + 25, {−5 &lt; <em>x</em> &lt; 5 &gt; 0}{−5 &lt; <em>y</em> &lt; 5}} &gt; 0</span>
<span
class="math display"><em>V</em><sub><em>i</em><em>s</em><em>c</em><em>i</em><em>r</em><em>c</em><em>l</em><em>e</em></sub> = 0</span>
<span
class="math display"><em>V</em><sub><em>i</em><em>s</em><em>c</em><em>i</em><em>r</em><em>c</em><em>l</em><em>e</em></sub> → {<em>V</em><sub><em>i</em><em>s</em><em>c</em><em>i</em><em>r</em><em>c</em><em>l</em><em>e</em></sub> = 0 : 1, 0}</span></p>
<p>Here, if you click the arrow button to the left of the last equation,
it will update/toggle <span
class="math inline"><em>V</em><sub><em>i</em><em>s</em><em>c</em><em>i</em><em>r</em><em>c</em><em>l</em><em>e</em></sub></span>.
An expression like <span
class="math inline">{<em>x</em> &gt; 0 : 42, 7}</span> is a conditional
expression but instead of 1 or undefined, it will return 42 when true
and 7 when false (i.e. if expression). Also, <span
class="math inline"><em>V</em><sub><em>i</em><em>s</em><em>c</em><em>i</em><em>r</em><em>c</em><em>l</em><em>e</em></sub> → {<em>V</em><sub><em>i</em><em>s</em><em>c</em><em>i</em><em>r</em><em>c</em><em>l</em><em>e</em></sub> = 0 : 1, 0}</span>
means when the action is triggered (button is clicked or via timer), it
will update the value which in this case would toggle between 0 and
1.</p>
<p>The action can also be connected to any object drawn on screen by
clicking the cog in the sidebar, clicking on the icon to the left of the
equation for the object and then enabling "Clickable".</p>
<p>You could also have that action be triggered every second (or
whatever interval) using the ticker feature in desmos (+ button in the
sidebar &gt; Ticker).</p>
<p>This post doesn't even begin to cover the incredible features desmos
provides but I think the fun is in exploring so if you find desmos
interesting, it's better to discover those yourself.</p>
<p><a target="_blank _parent" rel="noopener" href="https://desmos.ediblemonad.dev/#/graphs/snake-game">Here's
a snake game implemented in desmos</a>. Press "Play/Pause" to start.</p>
<p>I maintain my collection of desmos experiments
<a target="_blank _parent" rel="noopener" href="https://desmos.ediblemonad.dev">here</a>.</p>

]]>
</description></item>
<item><guid>2026-03-22-uiua</guid>
<title>Uiua</title>
<link>https://ediblemonad.dev/coding4fun/2026-03-22-uiua</link>
<comments>https://ediblemonad.dev/coding4fun/2026-03-22-uiua</comments>
<pubDate>2026-03-22</pubDate>
<description>
<![CDATA[
<h1 id="uiua">Uiua</h1>
<p><a target="_blank _parent" rel="noopener" href="https://www.uiua.org">Uiua</a>
is one of the most fun languages for creative coding. There are a bunch
of really good primitives for generating audio files from samples,
generating an image from an array of pixels, generating a gif from an
array of array of pixels, etc. Messed around with it
<a target="_blank _parent" rel="noopener" href="https://github.com/phenax/uiua-playground">here</a>
some time ago and I've started to miss it. The only other APL-ish
language I've tried is BQN which is also an amazing language but
thinking tacit is hard and it takes time to get used to. There are smart
people in the world. Being a member and representative of the other side
of that spectrum, I need my escape hatches and they need to be pleasant.
I've come to appreciate the stack-based escape hatches a lot more than
the functional escape hatches with blocks using 𝕩 and the other spicy
letters.</p>

]]>
</description></item>
<item><guid>2026-10-27-i-like-spiders</guid>
<title>I like spiders</title>
<link>https://ediblemonad.dev/random/2026-10-27-i-like-spiders</link>
<comments>https://ediblemonad.dev/random/2026-10-27-i-like-spiders</comments>
<pubDate>2026-10-27</pubDate>
<description>
<![CDATA[
<h1 id="i-like-spiders">I like spiders</h1>
<p>Something about spiders have always been interesting to me. I've
spent so many hours on wikipedia reading about spiders, that the spiders
have a restraining order against me.</p>
<p>Jumping spiders especially are wonderful. Incredibly cute little
guys. Have you ever stared at a jumping spider and they turn and lift
their heads to look at you? Fucking adorable. And don't get me started
on their "uppies" front leg lift when they're hopping up on your hands.
I've got a few jumping spiders around the house. Not pets, they just
live here.</p>
<p>They are incredibly smart, excellent hunters. They have object
permanence which is suprising for a brain that tiny. They have conical
eyes (hence the head lift to look at you), that they can use to focus on
fine details over long distances. Nature couldn't have come up with a
better design. It is really a treat to watch them wander around and
hunt.</p>
<p>The bigger ones although are intimidating. A few years ago I was
visited by a huntsman. He just entered my house like he owned the place
and for a second I considered moving. I knew he couldn't hurt me. He
wouldn't really want to bite me and even if he did, it would just be a
little swelling. But my instinct wouldn't let me get close. I ended up
using a shakey bowl (my hands weren't shaking, it was just a shakey
bowl) and a piece of cardboard to relocate him outside my window. But
after we had my window between us, I found the guy really beautiful and
impressive.</p>
<p>Another spider encounter was with a wood orb weaver spider when I was
visiting Kerala, India. I accidentally touched a bit of web between
branches that felt surprisingly strong, almost like a bit of thread. I
looked up and there was this magestic web between 2 trees with a giant
yellow, black patterned spider with a red dot on it's butt. That butt
comment felt innapropriate the moment I realized that it was a lady I
was looking at and the male of the spicies was the much smaller spider
on the web that I didn't even notice at first. Again scary as hell but I
couldn't stop looking. The patterns and her leg movements were
mesmerizing.</p>
<hr />

<table>
  <thead>
    <th>Jumping spider</th>
    <th>Huntsman</th>
    <th>Wood orb weaver</th>
  </thead>
  <tbody>
    <tr>
      <td><div class="image-container"><a target="_blank _parent" rel="noopener" href="/images/jumping.jpeg"><img style="max-height: 400px;" src="/images/jumping.jpeg" alt="Jumping spider" loading="lazy"></img></a></div></td>
      <td><div class="image-container"><a target="_blank _parent" rel="noopener" href="/images/huntsman.jpg"><img style="max-height: 400px;" src="/images/huntsman.jpg" alt="Huntsman" loading="lazy"></img></a></div></td>
      <td><div class="image-container"><a target="_blank _parent" rel="noopener" href="/images/wood-orb-weaver.jpg"><img style="max-height: 400px;" src="/images/wood-orb-weaver.jpg" alt="Wood orb weaver" loading="lazy"></img></a></div></td>
    </tr>
  </tbody>
</table>

<hr />

<p>Anyways, spiders are scary but pretty damn amazing.</p>

]]>
</description></item>
<item><guid>2026-10-14-make-public-executions-great-again</guid>
<title>Make public executions great again!</title>
<link>https://ediblemonad.dev/random/2026-10-14-make-public-executions-great-again</link>
<comments>https://ediblemonad.dev/random/2026-10-14-make-public-executions-great-again</comments>
<pubDate>2026-10-14</pubDate>
<description>
<![CDATA[
<h1 id="make-public-executions-great-again">Make public executions great
again!</h1>
<p>Ever since the Reign of Terror, I've been craving some good old
fashioned dramatic public executions. Hell yeah, bring that back!
Especially now that I don't have to walk all the way to the guillotine
and can just watch it online from the comfort and safety of my own home,
with my dick in my hand. Honestly kind of sick of watching things online
where no one dies. I need to feel something, damn it!</p>
<p>If you're one of those people with empathy, stop pretending. You
obviously only care about the people on your side. If you're one of
those people who <em>really</em> have empathy, relax a bit. The light
hitting the lens of the camera, travelling through the interent as bits,
and eventually turning into pixels drawn on your screen washes away all
meaning so at the end of the day, it's just a livestream, bro. Like
watching a scene from a movie where the bad guy dies. You don't have to
feel bad. If you still feel that way, try watching it 10 more times,
that'll fix your disability for sure. Or if you wait a few minutes,
you'll probably see a bunch of memes about it which is the best way to
stay up-to-date on current events since you can laugh about it and the
"too soon" laws don't apply. Humanity is evolving, get with the times or
go extinct, preferrably in front of a camera so I can watch.</p>
<p>If history repeats itself, it would be really fun to watch all the
kings' turn on the guillotine. Isn't this just a wonderful era we're a
part of?</p>

]]>
</description></item>
<item><guid>2026-06-07-nightmares-get-a-bad-rap</guid>
<title>Nightmares get a bad rap</title>
<link>https://ediblemonad.dev/random/2026-06-07-nightmares-get-a-bad-rap</link>
<comments>https://ediblemonad.dev/random/2026-06-07-nightmares-get-a-bad-rap</comments>
<pubDate>2026-06-07</pubDate>
<description>
<![CDATA[
<h1 id="nightmares-get-a-bad-rap">Nightmares get a bad rap</h1>
<p>Nightmares are so much fun! It's the most immersive horror movie
you've ever watched. Or a comedy-horror movie about how you're in school
again standing naked in front of all your classmates because you forgot
to wear your clothes and you realize that this is more than just about
your clothes. You exist in a perpetual state of shame with no end in
sight. You talk about acceptance but then use every chance you get to
criticize yourself for... Okay, I take it back, nightmares can be bad I
guess.</p>

]]>
</description></item>
<item><guid>2026-05-24-why-is-everything-broken-</guid>
<title>Why is everything broken?</title>
<link>https://ediblemonad.dev/random/2026-05-24-why-is-everything-broken-</link>
<comments>https://ediblemonad.dev/random/2026-05-24-why-is-everything-broken-</comments>
<pubDate>2026-05-24</pubDate>
<description>
<![CDATA[
<h1 id="why-is-everything-broken">Why is everything broken?</h1>
<p>I am the last person who would complain about bugs in tools I use.
Being a dev responsible for many bugs over the years, makes me empathize
with other devs so even the most frustrating buggy experiences I run
into ends with me going "eh, shit happens".</p>
<p>But recently, the web has been a bit more buggy that I'm used to.
Websites and apps just breaking all over the place. From the people I've
spoken to about this, I no longer think it's just me. The theory that
came up is all the AI-driven work done in the software industry but I
don't think that's it. As much as I dislike AI's forced involvement in
everything, I don't think the problem is just AI, but rather the effect
this is having on people. I think the disorientation from being pushed
in the deep end with AI is making experienced devs careless and hurting
our attention to detail.</p>
<p>Attention to detail is what I appreaciate about the output people
produce in the world. So people losing that makes us a lot less
interesting and apps a lot more useless. Hope that turns around.</p>

]]>
</description></item>
<item><guid>2026-05-14-all-consume--no-produce</guid>
<title>All consume, no produce</title>
<link>https://ediblemonad.dev/random/2026-05-14-all-consume--no-produce</link>
<comments>https://ediblemonad.dev/random/2026-05-14-all-consume--no-produce</comments>
<pubDate>2026-05-14</pubDate>
<description>
<![CDATA[
<h1 id="all-consume-no-produce">All consume, no produce</h1>
<p>Let's just stop creating. What has being creative actually got us,
really? Let's just consume. Time to replace every outlet that humans
have to produce any kind of output and turn that into an act of
consumption as well. We've already succeeded in doing that to all forms
of digital works - art, code, writing, videos, etc. but why stop there?
I took a shit earlier today, why even that? Let's pass a law that some
corporation owns all shit in the world and people are legally obligated
to buy it from them for permission to drop it out of their assholes.
Otherwise the corporation is well within their right to sue them for
damage to their property. Add a toilet-seat + flush monthly subscription
to that and boom, utopia!</p>

]]>
</description></item>
<item><guid>2026-05-12-the-powder-on-my-feet-can-go-fuck-itself</guid>
<title>The powder sticking to my feet can go fuck itself</title>
<link>https://ediblemonad.dev/random/2026-05-12-the-powder-on-my-feet-can-go-fuck-itself</link>
<comments>https://ediblemonad.dev/random/2026-05-12-the-powder-on-my-feet-can-go-fuck-itself</comments>
<pubDate>2026-05-12</pubDate>
<description>
<![CDATA[
<h1 id="the-powder-sticking-to-my-feet-can-go-fuck-itself">The powder
sticking to my feet can go fuck itself</h1>
<p>And the water after I wash my feet but at least that has the decency
to dry itself after a bit.</p>

]]>
</description></item>
<item><guid>2025-07-26-ed-it</guid>
<title>A case for ed</title>
<link>https://ediblemonad.dev/blog/2025-07-26-ed-it</link>
<comments>https://ediblemonad.dev/blog/2025-07-26-ed-it</comments>
<pubDate>2025-07-26</pubDate>
<description>
<![CDATA[
<h1 id="a-case-for-ed">A case for ed</h1>
<p>Can you say that you <strong>truly</strong> understand the tools you
use?</p>
<p>Text editors like vscode (or any other web browser as a text editor
things) or an IDE like intellij, are a russian doll for layers of
abstractions that you're meant to accept as a whole and never think
about. With something like vscode, there's the editor itself, all the
integrations that it comes with, the browser behind the scenes that
renders everything, some electron magic that connects that browser
internals to your system, whatever nodejs does, etc.</p>
<p>But as a programmer, that feeling is something that I've grown very
uncomfortable with. Which is partly why I've always gravitated towards
tools that are simple and let me break that abstraction and build around
it. The cost of that choice is of course that you have to trade off some
convinience to do this either as a one time investment to set it up or a
continuous cost if it's not very easy to use.</p>
<h3 id="prompt-driven-programming-before-ai">Prompt-driven programming
before AI</h3>
<p>Back in the day when people thought we'd have flying cars by the year
2025, the primary way to interact with a computer was through a teletype
interface. Not a fancy terminal emulator that allows displaying images
or one that asks you to sign-up with your email address to use your
terminal, just a regular ol' teletype terminal.</p>
<p>So an obvious choice to write code within this environment was an
editor that took commands for editing text and applied those commands on
the file. One such solution was a line-wise text editor called <a
href="https://linux.die.net/man/1/ed">ed</a>.</p>
<p>The way you edit text in ed is using commands in a repl interface
that operate on lines. You can
<strong>d</strong>elete/<strong>i</strong>nsert/<strong>a</strong>ppend/<strong>c</strong>hange/<strong>m</strong>ove/cop<strong>y</strong>
lines. If you want to change something inside a line you can use the
<strong>s</strong>ubstitute command <code>s/pattern/replacement/</code>.
There is also the <strong>g</strong>lobal command which applies one of
the other commands over all lines that match the given pattern. People
familiar with vim will already be familiar with a lot of these
commands.</p>
<h3 id="influence">Influence</h3>
<p>Not going into details of the history because if you can read this,
you can read wikipedia. But I can give you a lazy, poorly-researched
summary which is all you'll remember from wikipedia anyway.</p>
<ul>
<li>At first, there was <code>qed</code> which inspired
<code>ed</code></li>
<li>Then some dude said "want more" and went ahead and made
<code>ex</code></li>
<li>Then <code>ex</code> got a visual mode which became
<code>vi</code></li>
<li>Then came <a
href="https://en.wikipedia.org/wiki/Stevie_%28text_editor%29">stevie</a>,
a fork of vi for Atari ST</li>
<li>Then <code>vi</code> got <strong>im</strong>proved when stevie got
forked as <code>vim</code></li>
<li>Then finally we get the cool kid, neovim (<a
href="https://neovim.io/charter/">fork of vim</a>)</li>
<li>Also a side-note, almost all text editors come with a vi-mode as a
result of this chain of influence</li>
</ul>
<p>But that's not all</p>
<ul>
<li><code>sed</code> is essentially <code>ed</code>'s line-based editing
operations on streaming data (<strong>s</strong>tream
<strong>ed</strong>itor).</li>
<li><code>grep</code>'s name comes from a specific ed
<strong>g</strong>lobal command <code>g/re/p</code> which prints
everything that matches a given <strong>re</strong>gular
expression.</li>
<li>theres probably more things to add here but leaving this here
because I felt uncomfortable making a list of 2 items</li>
</ul>
<h3 id="modern-ux">Modern UX</h3>
<p>Having developed a lot of different user interfaces in my career,
I've come to the conclusion that modern user interfaces are designed for
idiots. Not saying, those interfaces are only used by idiots but they're
designed for the lowest common denominator of technologically inept.</p>
<blockquote>
<p>This button called 'Move to trash' will move your file to trash. If
you hover over it, it'll also show you a tooltip saying that it will
move your file to trash. Clicking on it will show you a dialog box
asking if you're absolutely sure that you want to move the file to
trash. If you click yes and then you realize that you want the file
back, you can go to the trash folder and restore it.</p>
</blockquote>
<p>Just <code>rm -rf</code> it, you pussy.</p>
<p>This is done not because, it's necessary but because the people
behind the tool pictured you as the worst case scenario of a user. They
imagined a user so incompetent with tech that they can't be trusted with
something they own. This reasoning is what then branches into a
justification for the lack of ownership with a lot of modern technology
but I'll leave some of this rambling to your imagination.</p>
<h3 id="simplicity">Simplicity</h3>
<p>I've always found ed to be quite elegant. Not because it's a good
tool to use but because of a very specific feeling associated with using
tools like this. Tools that are so simple that you feel like you
completely understand the underlying mechanics of it and not just as an
abstraction. You don't need a hand-wavy explanation for how it works. It
is obvious at first glance. There are a small set of primitives you
learn (commands in case of ed) and you know everything about how to use
the tool, how it works, and how to very accurately predict it's
behavior. If it breaks, it must've been a bit flip because a tool that
simple just can't break.</p>
<p>It's a breath of fresh air from all the high-level nonsense that
we've been fed all our lives in the 21st century that we learn to never
question and accept on faith. Not that far from religion, the way we
treat all the systems around us.</p>
<p>Like using a hammer. You look at it and you understand it. You don't
have to plug it into a wall. There's no installing updates to improve
security of the hammer. There's no sending usage data to some server in
the background to allow the hammer company to "improve" the tool.
Ignoring the quite likely kickstarter project doing those things, it's a
hammer. You hit things with it..</p>
<p>Most popular tools we use now are wrapped in so many layers of
abstraction that we are completely disconnected from the tools we rely
on. This trend is not acceptable to me.</p>
<h3 id="fun">Fun</h3>
<p>One of the biggest case I could make to try ed is that it's just fun.
It's an editor that feels very technical to use and provides enough
constraints to turn the experience of editing text into a turn-based
strategy game. You execute a few commands one after another, without
knowing if the edits are all correct and then you print the contents
inside ed and you feel the rush of getting it right! Or the
disappointment of forgetting to account for the added line in a previous
command.</p>
<h3 id="ai">AI</h3>
<p>We've sort of come full circle now. Prompts to edit text is back but
with the thickest layer of abstraction the world has every seen.</p>
<ul>
<li>You prompt it to make some edits, and it does that magically (among
other things).</li>
<li>You review the code (or don't if you're <em>really</em>
vibing).</li>
<li>You add it to your version control system (or don't if you're vibing
extra hard).</li>
<li>That's it. Do we really need a step here called "effort"?</li>
</ul>
<p>I cannot put into words worthy of a prompt to chatgpt, how extremely
unappealing this is to me.</p>
<p>Writing code and interacting with a computer in general has never
been a means to an end for me. That is the point. I write code because I
like writing code. Outsourcing that would be extremely pointless.</p>
<h3 id="inconclushun">Inconclushun</h3>
<p>Idk. Simple tools are fun. Bye.</p>

]]>
</description></item>
<item><guid>2023-02-13-ts-types-runtime</guid>
<title>TypeScript&#x27;s type-system as a runtime</title>
<link>https://ediblemonad.dev/blog/2023-02-13-ts-types-runtime</link>
<comments>https://ediblemonad.dev/blog/2023-02-13-ts-types-runtime</comments>
<pubDate>2023-02-13</pubDate>
<description>
<![CDATA[
<h1 id="typescripts-type-system-as-a-runtime">TypeScript's type-system
as a runtime</h1>
<blockquote>
<p>Disclaimer: The following content is not very informative</p>
</blockquote>
<p>Where were you on the night of 20th January? ANSWER ME, YOU FUCK! Not
a talker, yeah? No problem. You'll talk eventually. They all do.</p>
<p>We have an overwhelming amount of evidence that suggests that you
were the one responsible for turning typescript's type system into it's
own purely functional programming language. What kind of a sick, twisted
man, does that? You're gonna be spending a lot of time behind bars for
this.</p>
<p>The reports suggest that you can even read/write files, perform basic
io and even interop with js from it?</p>
<p>Take a look at some of the crime scene photos.</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode typescript"><code class="sourceCode typescript"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">export type</span> main <span class="op">=</span> [</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  PutStringLn<span class="op">&lt;</span><span class="st">&#39;Greetotron 6000 initializing...&#39;</span><span class="op">&gt;,</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  PutString<span class="op">&lt;</span><span class="st">&#39;Your name? &#39;</span><span class="op">&gt;,</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  Bind<span class="op">&lt;</span>ReadLine<span class="op">,</span> <span class="op">&lt;</span>name <span class="kw">extends</span> <span class="dt">string</span><span class="op">&gt;</span>() <span class="kw">=&gt;</span> PutStringLn<span class="op">&lt;</span><span class="vs">`Hello, </span><span class="sc">${</span>name<span class="sc">}</span><span class="vs">`</span><span class="op">&gt;&gt;,</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>  PutString<span class="op">&lt;</span><span class="st">&#39;Your purpose in life? &#39;</span><span class="op">&gt;,</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  Bind<span class="op">&lt;</span>ReadLine<span class="op">,</span> HandleResponse<span class="op">&gt;,</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>  PutStringLn<span class="op">&lt;</span><span class="st">&#39;Bye bye&#39;</span><span class="op">&gt;,</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>]</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="co">// Equivalent to `HandleResponse :: string -&gt; Effect ()`</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a><span class="kw">interface</span> HandleResponse <span class="kw">extends</span> Kind1<span class="op">&lt;</span><span class="dt">string</span><span class="op">,</span> Effect<span class="op">&gt;</span> {</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span><span class="op">:</span> Do<span class="op">&lt;</span>[</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>    PutStringLn<span class="op">&lt;</span><span class="vs">`Interesting that you believe &quot;</span><span class="sc">${</span><span class="kw">this</span>[<span class="st">&#39;input&#39;</span>]<span class="sc">}</span><span class="vs">&quot; is your purpose. Hmmmm...`</span><span class="op">&gt;,</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>    PutStringLn<span class="op">&lt;</span><span class="st">&#39;Judging harshly...&#39;</span><span class="op">&gt;,</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>    PutStringLn<span class="op">&lt;</span><span class="st">&#39;Saving response...&#39;</span><span class="op">&gt;,</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>    WriteFile<span class="op">&lt;</span><span class="st">&#39;./response.txt&#39;</span><span class="op">,</span> <span class="kw">this</span>[<span class="st">&#39;input&#39;</span>]<span class="op">&gt;,</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>  ]<span class="op">&gt;</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>Do you feel any remorse for the victims you've affected? I hope you
get the chair for this.</p>
<p>We also found the murder weapon on the crime scene -
<code>npx tsr run ./somefile.ts</code>. Not just that, it says here you
built the weapon yourself using <code>ts-morph</code> as a wrapper
around the typescript compiler. Did you use the source file as your
runtime representation of memory, you piece of shit?! But, we're getting
a bit ahead of ourselves here.</p>
<p>Let's get to the motive which is the only piece of the puzzle we're
missing. Why would a mediocre software developer suddenly go postal and
make something like this? Did someone pay you to do this? Is that what
this is about? Money? Naah. This was a little more personal than that. I
have a theory for why you did it. And it's as simple as it gets. You're
a sick man who enjoys watching people cringe and suffer. Is that what
this blog post is about? More cringe?</p>
<p>We've even figured out how you smuggled all the results of the io
back into the program. It was a result node, wasn't it? A stray object
that you injected properties into, you sick fuck. Was that your runtime
representation of memory? You just used the randomly generated property
name to access the result in your effects.</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode typescript"><code class="sourceCode typescript"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> __$result <span class="op">=</span> {</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="st">&#39;90sd9...&#39;</span><span class="op">:</span> { output<span class="op">:</span> <span class="st">&#39;Result of computation&#39;</span> }</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>Another thing that's been bugging me is,</p>
<h3 id="why-is-the-effects-api-monadic">Why is the effects api
monadic?</h3>
<p>Was it because you wanted all operations on the results represented
in the type tree so you could manipulate it?</p>
<p>You disgust me. In my 20 years on the force, I've never met a man as
disturbed as you. Don't bother pleading insanity here though. This was
calculated. No one is going to buy it.</p>
<h3 id="remember-your-hacky-attempts-at-first-class-functions">Remember
your hacky attempts at first class functions?</h3>
<p>We have it in our custody and it's talking like a parrot. Telling us
everything we need to know about your sick experiments!</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode typescript"><code class="sourceCode typescript"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">interface</span> Greet <span class="kw">extends</span> Kind1<span class="op">&lt;</span><span class="dt">string</span><span class="op">,</span> <span class="dt">string</span><span class="op">&gt;</span> {</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span><span class="op">:</span> <span class="vs">`Hello, </span><span class="sc">${</span><span class="kw">this</span>[<span class="st">&#39;input&#39;</span>]<span class="sc">}</span><span class="vs">!`</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> msg <span class="op">=</span> Apply<span class="op">&lt;</span>Greet<span class="op">,</span> <span class="st">&#39;EdibleMonad&#39;</span><span class="op">&gt;</span> <span class="co">// : &#39;Hello, EdibleMonad!&#39;</span></span></code></pre></div>
<p>Yeah, we got you now, you bastard!</p>
<p>You weren't satisfied with this tho, were you? You wanted your
first-class functions to be inline. You needed it. So you made your
runtime recognize lambda functions as first-class functions.</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode typescript"><code class="sourceCode typescript"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> main <span class="op">=</span> Bind<span class="op">&lt;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  ReadFile<span class="op">&lt;</span><span class="st">&#39;./file.txt&#39;</span><span class="op">&gt;,</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">&lt;</span>T <span class="kw">extends</span> <span class="dt">string</span><span class="op">&gt;</span>() <span class="kw">=&gt;</span> PutStringLn<span class="op">&lt;</span>T<span class="op">&gt;</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span></span></code></pre></div>
<p>But this is where you fucked up. You couldn't generalize this as a
pattern because typescript doesn't work like that. Typescript doesn't
support higher kinded types, dumbass! So you settled for only allowing
this pattern inside <code>Bind</code> and <code>Try</code>. You flew too
close to the sun, Icarus and it lead us straight to you.</p>
<p>You're done, buddy. This case is as good as closed so you might as
well confess.</p>
<h3 id="alright-alright-i-confess">Alright! Alright! I confess!</h3>
<p>It was me who did it. I made the runtime that turns typescript types
into a purely functional programming language! I did it because I
fucking wanted to! And I enjoyed every second of it!</p>
<p>I saw people making things that defied all logic, like an <a
href="https://github.com/judehunter/ts-asm">assembly interpreter</a>
within the typescript type-system. I knew if I wanted to make it do
something more, I'll need a runtime! That's when I came up with my
master plan.</p>
<p>I don't regret a thing! I've made my mark on the world even if that
mark is a piss stain on the side of the street.</p>
<hr />
<blockquote>
<p>Akshay was charged with cringe and sentenced to death by lethal
injection. It was later discovered that this wasn't all that big of a
deal and completely blown out of proportion.</p>
</blockquote>
<p>Ok bye</p>

]]>
</description></item>
<item><guid>2021-03-01-effect-handlers</guid>
<title>Designing effects as data structures</title>
<link>https://ediblemonad.dev/blog/2021-03-01-effect-handlers</link>
<comments>https://ediblemonad.dev/blog/2021-03-01-effect-handlers</comments>
<pubDate>2021-03-01</pubDate>
<description>
<![CDATA[
<h1 id="designing-effects-as-data-structures">Designing effects as data
structures</h1>
<p>You gotta teach your effects some manners.</p>
<p>We work with effects everyday, but those rascals have a habit of
running around loose in our programs. I'm not saying it's just bad
parenting but we have to draw the line at some point.</p>
<p>Look at pure functions, they are so disciplined and obedient. They
never get into any trouble. You ask them a question, they give you an
answer. That's what you expect from good code. If you find out that your
function, while giving you the answer, also went ahead and made 5 api
calls, thats a good sign that your code needs some disciplining.</p>
<hr />
<h3 id="lets-implement-a-linked-list">Let's implement a linked list</h3>
<p>I swear this is relevant and not a plot to make you learn DSA
again.</p>
<pre class="reasonml"><code>type rec myList&lt;&#39;a&gt; = Nil | Cons(&#39;a, myList&lt;&#39;a&gt;)

let ls = Cons(5, Cons(20, Cons(-28, Nil)))</code></pre>
<p>That is a simple <strong>linked list</strong> implemented in <a
href="https://rescript-lang.org/">rescript</a>. <code>Nil</code> marks
the end of the list and every element before it contains an item of that
list and the rest of the list. They know how to stand in a straight line
like good students.</p>
<p>But, this is an <strong>eager list</strong> since all items of the
list already exist on the time of its creation. For what we're working
on today, eager lists won't be enough. We need our list to be
<em>lazy</em>. We can turn that into a <strong>lazy linked list</strong>
by replacing the rest of the list with a function returning the rest of
the list like so -</p>
<pre class="reasonml"><code>type rec lazyList&lt;&#39;a&gt; = Nil | Cons(&#39;a, unit =&gt; lazyList&lt;&#39;a&gt;)

let ls = Cons(5, () =&gt;
  Cons(20, () =&gt;
    Cons(512, () =&gt;
      Nil)))</code></pre>
<p>This makes it so the rest of the linked list doesn't exist till the
function is called. This is helpful if you wanted to create an
<strong>infinite list</strong>.</p>
<pre class="reasonml"><code>let rec fibonacci = (a, b) =&gt; Cons(b, () =&gt; fibonacci(b, a + b))

let rec take = (ls, n) =&gt; switch (n, ls) {
  | (_, Nil) | (0, _) =&gt; Nil
  | (n, Cons(value, next)) =&gt; Cons(value, () =&gt; next()-&gt;take(n - 1))
}

let rec forEach = (ls, fn) =&gt; switch ls {
  | Nil =&gt; ()
  | Cons(value, next) =&gt; {
    fn(value)
    next()-&gt;forEach(fn)
  }
}

fibonacci(0, 1)-&gt;take(20)-&gt;forEach(Js.log)</code></pre>
<p><code>fibonacci</code> returns a lazy list of all the numbers in
Fibonacci series starting with <code>a</code> and <code>b</code>. We
then use the <code>take</code> function to ignore the list after the
first <code>20</code> items. <code>forEach</code>, then goes through the
new list till the 20 items and logs each one out.</p>
<p>This is very helpful for <strong>modeling continuous
sequences</strong> of data without consuming all the space it may
need.</p>
<p>Everything we've played with so far has been <em>simple</em> and
<em>pure</em>. Unlike those disobedient effects passing notes to each
other, non-deterministically. Oh I hate them so much.</p>
<hr />
<h3 id="can-effects-be-more-like-that">Can effects be more like
that?</h3>
<p>Close your eyes. No, seriously, close them. This is important. Now,
imagine a world where all your effectful code could just be designed as
<em>data structures</em>! Are your eyes still closed? Good. Something as
simple as a linked list that describes all the effectful logic in your
code. Writing tests will become fun! Everything would be so much
simpler. All of our life's problems would just disappear.</p>
<p>Well, today's yo... Oh you can open your eyes now. Sorry. Well,
today's your lucky day!</p>
<p>We will turn your ill-mannered effects into well behaved pure data
structures.</p>
<hr />
<h3 id="impure-effect-more-like-code-neglect-amirite-please-clap">Impure
effect? More like code neglect, amirite? Please clap</h3>
<p>Kids, please turn in your assignment from last week. I hope you all
implemented
<code>appendStringToFile: string =&gt; string =&gt; string</code> that
appends a string to a file and returns the new contents, given the
imaginary synchronous functions
<code>readFile: string =&gt; string</code> and
<code>writeFile: string =&gt; string =&gt; ()</code> for doing file
IO.</p>
<pre class="reasonml"><code>let appendStringToFile = (fileName, logLine) =&gt; {
  let contents = readFile(fileName)
  writeFile(contents ++ logLine)
  readFile(fileName)
}

let newLogContents = appendStringToFile(fileName, &quot;\nSome text&quot;)</code></pre>
<p>Oh my god, Timmy! Is that imperative and impure function calls in
your notebook? That's it. To the principals office! Now!</p>
<p>Now let's try to think of a way to do this that's not an absolute
nightmare to test. What if we just made a data structure out of it?</p>
<p>Let's try turning each of those statements into variants that can be
linked together lazily.</p>
<pre class="reasonml"><code>type rec fileEff&lt;&#39;a&gt; =
  | ReadFile(string, string =&gt; fileEff&lt;&#39;a&gt;)
  | WriteFile(string, string, unit =&gt; fileEff&lt;&#39;a&gt;)
  | Return(string)

let appendStringToFile = (fileName, logLine) =&gt;
  ReadFile(fileName, contents =&gt;
    WriteFile(fileName, contents ++ logLine, _ =&gt;
      ReadFile(fileName, newContents =&gt;
        Return(newContents))))</code></pre>
<p>You can read <code>Something(a, b, c =&gt; fileEff&lt;'a&gt;)</code>
as an operation <code>Something</code> that takes <code>a</code> and
<code>b</code> and returns a <code>c</code>.</p>
<p>If you squint hard enough, you'll find that this is very similar to
the <strong>lazy list</strong> data structure we implemented earlier.
You have the last item <code>Return</code>, and each item before it is a
description of an effect.</p>
<p>This is similar to how programming languages have <strong>Abstract
Syntax Trees (AST)</strong> that describe the syntax of the language
which then goes through the <strong>interpreter</strong> to be executed.
Just like ASTs, to get our code working, we need to write an interpreter
to evaluate our data structure and produce effects.</p>
<pre class="reasonml"><code>let rec interpreter = eff =&gt; switch eff {
  | Return(contents) =&gt; contents
  | ReadFile(fileName, getNext) =&gt;
    readFile(fileName)-&gt;getNext-&gt;interpreter
  | WriteFile(fileName, contents, getNext) =&gt; {
    writeFile(fileName, contents);
    ()-&gt;getNext-&gt;interpreter;
  }
}

let result = interpreter(appendStringToFile(&quot;./file&quot;, &quot;hello world&quot;));</code></pre>
<p>The interpreter walks through the list-like structure and calls
itself recursively on each of the nodes till it hits
<code>Return</code>.</p>
<p>Kevin: "Why is this better than writing it imperatively?"</p>
<p>*takes a deep breath* Kevin... STFU!</p>
<p>This is better because it <strong>decouples</strong> your
<strong>business logic</strong> from the <strong>effects</strong>! This
is better because you can just create a <strong>mock
interpreter</strong> and <strong>write tests for your business
logic</strong> without actually generating effects! This is better
because you get <strong>dependency injection</strong> for free!</p>
<hr />
<h3 id="are-we-composable-yet">Are we composable yet?</h3>
<p>Now we have a new problem though. It seems like <code>Return</code>
will have to be defined for every kind of effect we may have. This will
also make it difficult to <strong>compose</strong> it with other
effects. So let's abstract that out.</p>
<p>We can create a module function for creating effects and handling the
recursion in the interpreter.</p>
<pre class="reasonml"><code>module type EFFECT = {
  type t&lt;&#39;a&gt;
}

module MakeEffect = (Eff: EFFECT) =&gt; {
  type rec t&lt;&#39;a, &#39;ret&gt; = 
    | Return(&#39;ret)
    | Operation(Eff.t&lt;t&lt;&#39;a, &#39;ret&gt;&gt;)

  let rec interpreter = (eff, handler) =&gt; switch eff {
    | Return(x) =&gt; x
    | Operation(m) =&gt; handler(m)-&gt;interpreter(handler)
  }
}</code></pre>
<p>Then we can rewrite our file effect in peace.</p>
<pre class="reasonml"><code>module FileOperations = {
  type t&lt;&#39;a&gt; =
    | ReadFile(string, string =&gt; &#39;a)
    | WriteFile(string, string, unit =&gt; &#39;a)
}

module FileEffect = MakeEffect(FileOperations)

let appendStringToFile = (fileName, logLine) =&gt; {
  open FileOperations;
  open FileEffect;

  Operation(ReadFile(fileName, contents =&gt;
    Operation(WriteFile(fileName, contents ++ logLine, _ =&gt;
      Operation(ReadFile(fileName, contents =&gt;
        Return(contents)
      ))
    ))
  ))
}

let handler = eff =&gt; switch eff {
  | ReadFile(fileName, resume) =&gt; readFile(fileName)-&gt;resume;
  | WriteFile(fileName, contents, resume) =&gt; {
    writeFile(fileName, contents);
    resume(());
  }
}

let result = appendStringToFile-&gt;FileEffect.interpreter(handler)</code></pre>
<blockquote>
<p><strong>"Effects as a data structure is cool and all but I don't want
to write code that looks like a ladder"</strong> - Former student who
died under suspicious circumstances shortly after making this
statement</p>
</blockquote>
<p>I get it. It looks ugly. All new-born babies do. We just need some
<em>SYNTAX SUGAR</em> to make things better. Don't worry tho. I got you.
But before we go there, we need to implement a <code>flatMap</code>
operation for our effect.</p>
<p>You may know <code>flatMap</code> from it's critically acclaimed role
in <code>Belt.Option</code> and <code>Belt.Result</code> modules. Also,
the horrible <code>Js.Promise.then_</code>, is also a
<code>flatMap</code> on promises. In general,
<code>flatMap: t&lt;'a&gt; =&gt; ('a =&gt; t&lt;'b&gt;) =&gt; t&lt;'b&gt; </code>
allows us to chain <code>t&lt;'a&gt;</code> to <code>t&lt;'b&gt;</code>
using the result of <code>t&lt;'a&gt;</code>.</p>
<pre class="reasonml"><code>// This is a map operation over our file operation
let fileOpsMap = (eff, fn) =&gt; switch eff {
  | ReadFile(f, next) =&gt; ReadFile(f, e =&gt; e-&gt;next-&gt;fn)
  | WriteFile(f, c, next) =&gt; WriteFile(f, c, e =&gt; e-&gt;next-&gt;fn)
}

// This function allows us to chain our effects together
let rec flatMap = (eff, fn) =&gt; switch eff {
  | Return(a) =&gt; fn(a)
  | Eff(m) =&gt; Eff(m-&gt;fileOpsMap(flatMap(_, fn)))
}</code></pre>
<p>While we're at it, we'll also need another function called
<code>liftEff</code>. This function <strong>lifts</strong> any given
operation into an <code>Effect</code> and makes it terminate with its
result. <code>x =&gt; next effect?</code> becomes
<code>Eff(x =&gt; Return(x))</code></p>
<pre class="reasonml"><code>let liftEff = fa =&gt; Eff(fa-&gt;fileOpsMap(e =&gt; Return(e)));</code></pre>
<p>Now putting it all together, our effects helper and file effect will
look something like this</p>
<pre class="reasonml"><code>module type EFFECT = {
  type rec t&lt;&#39;a&gt;;
  let map : t&lt;&#39;a&gt; =&gt; (&#39;a =&gt; &#39;b) =&gt; t&lt;&#39;b&gt;;
};

module MakeEffect = (Eff: EFFECT) =&gt; {
  type rec t&lt;&#39;a&gt; = 
    | Return(&#39;a)
    | Eff(Eff.t&lt;t&lt;&#39;a&gt;&gt;);

  let liftEff = fa =&gt; Eff(fa-&gt;Eff.map(e =&gt; Return(e)));

  let rec flatMap = (eff, fn) =&gt; switch eff {
    | Return(a) =&gt; fn(a)
    | Eff(m) =&gt; Eff(m-&gt;Eff.map(flatMap(_, fn)))
  };

  let rec interpreter = (eff, handler) =&gt; switch eff {
    | Return(x) =&gt; x
    | Eff(m) =&gt; handler(m)-&gt;interpreter(handler)
  };
};

module FileOperations = {
  type rec t&lt;&#39;a&gt; =
    | ReadFile(string, string =&gt; &#39;a)
    | WriteFile(string, string, unit =&gt; &#39;a);

  let map = (eff, fn) =&gt; switch eff {
    | ReadFile(f, next) =&gt; ReadFile(f, e =&gt; e-&gt;next-&gt;fn)
    | WriteFile(f, c, next) =&gt; WriteFile(f, c, e =&gt; e-&gt;next-&gt;fn)
  };
};

module FileEffect = MakeEffect(FileOperations);

// Lifted helper functions
let readFileOp = file =&gt;
  FileEffect.liftEff(FileOperations.ReadFile(file, x =&gt; x));

let writeFileOp = (file, contents) =&gt;
  FileEffect.liftEff(FileOperations.WriteFile(file, contents, x =&gt; x));</code></pre>
<p>Now for the <em>SYNTAX SUGAR</em> I promised!</p>
<pre class="reasonml"><code>let appendStringToFile = (fileName, logLine) =&gt; {
  open FileEffect;

  readFileOp(fileName)
  -&gt;flatMap(contents =&gt; writeFileOp(fileName, contents ++ logLine))
  -&gt;flatMap(_ =&gt; readFileOp(fileName))
};</code></pre>
<p>We have turned our <code>FileOperations</code> into a functor</p>
<hr />
<h3 id="no-not-that-functor-the-other-functor">No, not that functor, the
other functor.</h3>
<p>Functors in ocaml (<a
href="https://rescript-lang.org/docs/manual/latest/module#module-functions-functors">module
functions</a>) are very different from functors in category theory.</p>
<p>What we have made here is a combination of both kinds of functors.
The <code>FileOperations</code> <strong>functor</strong> (category
theory) goes into the <code>MakeEffect</code> <strong>functor</strong>
(module function) and returns <code>FileEffect</code>
<strong>monad</strong> (category theory).</p>
<blockquote>
<p>Fun fact: Functor comes from the contraction of, fun which is Russian
for vodka, ca which of course is the sound a crow makes and tor which is
a modern tin foil hat that actually works.</p>
</blockquote>
<blockquote>
<p>Fun fact: Monad comes from the mind of a mathematician who forgot
about the essay that was due, so at the last minute, started making up
words to fill up the 800 words.</p>
</blockquote>
<p>Don't quote me on that but it's probably true. We'll never know.</p>
<p>We don't have to get into the specifics of functors and monads to
make sense of this class but it is worth the learning curve.</p>
<hr />
<h3 id="ugh-unit-tests">Ugh.. Unit tests</h3>
<p>Writing tests for it is as simple as creating <strong>a mock
handler</strong>.</p>
<pre class="reasonml"><code>let mockFile = ref(&quot;init:&quot;);
let mockHandler = eff =&gt; switch eff {
  | FileOperations.ReadFile(fileName, resume) =&gt; resume(mockFile.contents);
  | FileOperations.WriteFile(fileName, contents, resume) =&gt; {
    mockFile.contents = contents;
    resume(());
  };
};

let result = appendStringToFile(&quot;./file&quot;, &quot;text to append&quot;)
  -&gt;FileEffect.interpreter(mockHandler);

expect.string(result).toEqual(&quot;init:text to append&quot;);
expect.string(mockFile.contents).toEqual(&quot;init:text to append&quot;);</code></pre>
<p>And now for the best part... <em>drum rolls</em></p>
<p><strong>SNAPSHOT/GOLDEN TESTING</strong></p>
<p>Yes! As all our business logic is now just a data structure, you can
create a snapshot of it to test against!</p>
<p>You can perform snapshot testing of your effect by
<strong>accumulating the effects</strong> called on your handler as an
array.</p>
<pre class="reasonml"><code>let nodes = ref([]-&gt;Obj.magic);
let addNode = node =&gt; nodes.contents = nodes.contents-&gt;Belt.Array.concat([node]);

let mockHandler = eff =&gt; {
  addNode(eff);
  switch eff {
    | FileOperations.ReadFile(_f, resume) =&gt; resume(&quot;mock file contents&quot;)
    | FileOperations.WriteFile(_f, _c, resume) =&gt; resume(())
  };
};

appendStringToFile(&quot;./file&quot;, &quot;text to append&quot;)-&gt;FileEffect.interpreter(mockHandler)-&gt;ignore;

expect.value(nodes).toMatchSnapshot();</code></pre>
<p>And just like that, all of our business logic is now 100% safe
against all kinds of refactor.</p>
<ul>
<li>You change the order of effects?... Tests break!</li>
<li>You add another effect in between?... Tests break!</li>
<li>You accidentally delete everything?... Tests explodes!</li>
<li>You got scammed by a Nigerian prince?... This won't help with
that!</li>
<li>You change something that doesn't impact your program?... Tests
pass!</li>
</ul>
<hr />
<h3 id="effect-composition">Effect composition</h3>
<p>File IO is great but your code will involve other effects too. Maybe
you want to implement <strong>logging</strong>? Or maybe some
<strong>caching</strong> mechanism? Or maybe you just want to maintain a
piece of <strong>mutable state</strong> in your code? Just having one
effect called <code>FileEffect</code> is not gonna cut it.</p>
<p>To be able to compose multiple effects into one big effect, we can
use the almighty <a
href="https://rescript-lang.org/docs/manual/latest/polymorphic-variant">STRUCTURAL/POLYMORPHIC
VARIANTS</a>!</p>
<pre class="reasonml"><code>// File IO effect
module FileOperations = {
  type rec t&lt;&#39;a&gt; = [ #ReadFile(string, string =&gt; &#39;a) | #WriteFile(string, string, unit =&gt; &#39;a) ];

  let map = (eff, fn) =&gt; switch eff {
    | #ReadFile(f, next) =&gt; #ReadFile(f, e =&gt; e-&gt;next-&gt;fn)
    | #WriteFile(f, c, next) =&gt; #WriteFile(f, c, e =&gt; e-&gt;next-&gt;fn)
  };
};

// Logger effect
module LoggerOperations = {
  type rec t&lt;&#39;a&gt; = [ #LogMessage(string, string, string =&gt; &#39;a) ];

  let map = (eff, fn) =&gt; switch eff {
    | #LogMessage(m, d, next) =&gt; #LogMessage(m, d, e =&gt; e-&gt;next-&gt;fn)
  };
};

// Composition of FileOperations and LoggerOperations
module MyCustomOperations = {
  type rec t&lt;&#39;a&gt; = [ LoggerOperations.t&lt;&#39;a&gt; | FileOperations.t&lt;&#39;a&gt; ];

  let map = eff =&gt; switch eff {
    | #...FileOperations.t as e =&gt; FileOperations.map(e)
    | #...LoggerOperations.t as e =&gt; LoggerOperations.map(e)
  };
};

module MyCustomEff = MakeEffect(MyCustomOperations);

let logMessageOp = (message, data) =&gt; MyCustomEff.liftEff(#LogMessage(message, data, x =&gt; x));
let readFileOp = file =&gt; MyCustomEff.liftEff(#ReadFile(file, x =&gt; x));
let writeFileOp = (file, contents) =&gt; MyCustomEff.liftEff(#WriteFile(file, contents, x =&gt; x));

// Our program
let appendStringToFile = (fileName, logLine) =&gt; {
  open MyCustomEff;

  readFileOp(fileName)
  -&gt;flatMap(logMessageOp(&quot;:: Logging file contents before update -&quot;))
  -&gt;flatMap(contents =&gt; writeFileOp(fileName, contents ++ logLine))
  -&gt;flatMap(_ =&gt; readFileOp(fileName))
  -&gt;flatMap(logMessageOp(&quot;:: Logging file contents after update -&quot;))
};</code></pre>
<p>You can <strong>compose any number of effects</strong> together into
one for your programs!</p>
<p>And of course, nothing would work without the handler so...</p>
<pre class="reasonml"><code>let handler = eff =&gt; switch eff {
  | #LogMessage(message, data, resume) =&gt; {
    Js.log2(message, data);
    resume(data);
  }
  | #ReadFile(fileName, resume) =&gt; readFile(fileName)-&gt;resume;
  | #WriteFile(fileName, contents, resume) =&gt; {
    writeFile(fileName, contents);
    resume(());
  };
};

let result = appendStringToFile-&gt;MyCustomEff.interpreter(handler);</code></pre>
<hr />
<h3 id="does-all-of-this-have-a-name">Does all of this have a name?</h3>
<p>What we just learned is a construct in functional programming called
<a href="https://wiki.haskell.org/Free_structure">free algebraic
structures</a>. More specifically, <code>FileEffect</code> and
<code>MyCustomEff</code> are Free Monads.</p>
<p>In general, a free monad on a Functor <code>f</code> is a structure
where each node represents <code>f</code>. If you understood what I just
said, please explain it to me after class so I don't look like an idiot
in front of my other students.</p>
<p>In this class, we used it to <strong>fold</strong> (interpret) a data
structure to generate effects. It allowed us to decouple the composition
of our effects with the effect's behavior by creating a pure
representation of our computations.</p>
<p>Free monad implementation for dealing with effects in such a way is
also referred to as <a
href="https://overreacted.io/algebraic-effects-for-the-rest-of-us/">algebraic
effects</a>.</p>
<p>To learn more about this, you could walk through the following links
-</p>
<ul>
<li><a
href="https://rescript-lang.org/docs/manual/latest/module#module-functions-functors">What
the fuck are module functions/functors?</a></li>
<li><a
href="https://medium.com/@dtinth/what-is-a-functor-dcf510b098b6">What
the fuck is a Functor in category theory?</a></li>
<li><a href="https://wiki.haskell.org/All_About_Monads">What the fuck is
a Monad?</a></li>
<li><a href="https://wiki.haskell.org/Free_structure">What the fuck are
Free Algebraic Structures?</a></li>
<li><a
href="https://overreacted.io/algebraic-effects-for-the-rest-of-us/">What
the fuck are algebraic effects?</a></li>
</ul>
<hr />
<h3 id="report-card">Report card</h3>
<p>Our jobs as programmers is to create as many
<strong>guarantees</strong> in our code as possible. To achieve this, we
should always try to design things in a way that pushes everything we
can't guarantee to the edges.</p>
<p>This not only reduces the <strong>surface area for bugs</strong>, but
also reduces the <strong>mental overhead</strong> to the person reading
the code.</p>
<p>This is why we should always try to minimize the surface area of
impurity in our code.</p>
<p>With free monads, we create a guarantee that our business logic is
sound and we push the effects to the edge in the form of our interpreter
since we may not be able to guarantee the correctness of effectful
behavior.</p>
<p>Anyways, impure programs get a C for "Can do better". Almost-pure
programs with Free monads, get an A for "Aahaaa, functional programming
wins again".</p>
<p>Alright kids, get a signature on the report card from your parents.
No fake signatures, John. Those squiggly lines aren't fooling
anyone.</p>

]]>
</description></item>
<item><guid>2019-03-29-js-magic</guid>
<title>JS Magic Tricks to impress your friends</title>
<link>https://ediblemonad.dev/blog/2019-03-29-js-magic</link>
<comments>https://ediblemonad.dev/blog/2019-03-29-js-magic</comments>
<pubDate>2019-03-29</pubDate>
<description>
<![CDATA[
<h1 id="js-magic-tricks-to-impress-your-friends">JS Magic Tricks to
impress your friends</h1>
<p>My name is Houdini J.S. Magnifico. What I'm about to perform here are
a set of illusions and magic tricks that are sure to blow your mind! So
prepare to be amazed!</p>
<blockquote>
<p>The tricks shown here are performed by trained professionals. Do not
attempt these stunts at home. Do it in production. Viewer discretion is
advised.</p>
</blockquote>
<p>Let the show begin!</p>
<hr />
<h3 id="for-my-first-trick-i-will-make-this-function-disappear">For my
first trick, I will make this function… DISAPPEAR!</h3>
<p>This is my totally normal function. Nothing weird about it. A
function you'd find in the wild.</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">typeof</span> innocentTotallyNormalFunction <span class="op">===</span> <span class="st">&quot;function&quot;</span> <span class="co">// &gt; true</span></span></code></pre></div>
<p>Let me just wave Brendan Eich's mouse pad over it for a bit… and…
BOOM!</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">innocentTotallyNormalFunction</span>()</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="co">// &gt; Uncaught TypeError: innocentTotallyNormalFunction is not a function</span></span></code></pre></div>
<p>GONE! The function is not a function anymore. Schrodinger's function
has dissappeared!</p>
<p><strong><em>audience applauds</em></strong></p>
<p>Thank you! Thank you!</p>
<h4 id="heres-how-it-works">Here's how it works</h4>
<div class="sourceCode" id="cb3"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> innocentTotallyNormalFunction <span class="op">=</span> (() <span class="kw">=&gt;</span> {})<span class="op">.</span><span class="at">apply</span><span class="op">.</span><span class="fu">bind</span>()<span class="op">;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="co">// Works with any method&#39;s bind();</span></span></code></pre></div>
<p>Weird right? It's called JavaScript and a lot of people use this in
production. The reason this doesn't work is because .apply method
expects the context of a function but .bind gives it undefined as the
context. this.means that the apply method doesn't know which function it
is trying to apply. Then the apply method has an identity crisis and
everything goes to shit.</p>
<hr />
<h3 id="magic-list">Magic list</h3>
<p>Here I have a function that clones an array. Perfectly normal,
production ready code.</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> clone <span class="op">=</span> list <span class="kw">=&gt;</span> list<span class="op">.</span><span class="fu">reduce</span>((newList<span class="op">,</span> item) <span class="kw">=&gt;</span> [<span class="op">...</span>newList<span class="op">,</span> item]<span class="op">,</span> [])<span class="op">;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="co">// Another clone implementation you can use is,</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> clone <span class="op">=</span> <span class="bu">Object</span><span class="op">.</span><span class="at">values</span><span class="op">;</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="co">// Or if you wanna go old school...</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> clone <span class="op">=</span> list <span class="kw">=&gt;</span> {</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> newList <span class="op">=</span> []<span class="op">;</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span>(<span class="kw">let</span> index <span class="kw">in</span> list) {</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>    newList<span class="op">.</span><span class="fu">push</span>(list[index])<span class="op">;</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> newList<span class="op">;</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>}<span class="op">;</span></span></code></pre></div>
<p>Here's an ordinary list with nothing fishy going on inside</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>array<span class="op">.</span><span class="at">length</span> <span class="co">// &gt; 23</span></span></code></pre></div>
<p>I'm just gonna casually use the clone function to copy the list and
check the length of the newly created list…</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="fu">clone</span>(array)<span class="op">.</span><span class="at">length</span> <span class="co">// &gt; 1</span></span></code></pre></div>
<p><strong>Magic!!</strong></p>
<p>The list is no longer 23 items long. 23 to 1! Next-gen compression
algorithm, question mark? Or is it just magic?</p>
<h4 id="well-heres-how-it-all-went-down">Well, here's how it all went
down</h4>
<p>The concept behind this is one that not many developers are familiar
with. Array holes, also called empty slots are points in an array that
are empty. No, I'm not talking about undefined or null or 0. Just
empty.</p>
<p>Ref: <a href="https://2ality.com/2015/09/holes-arrays-es6.html">Array
holes/empty slots</a>, <a
href="https://2ality.com/2012/06/dense-arrays.html">Sparse
arrays</a></p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="bu">Array</span>(<span class="dv">5</span>) <span class="co">// &gt; [&lt;empty x 5&gt;]</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="co">// OR</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>[<span class="op">,,,,,</span>] <span class="co">// &gt; [&lt;empty x 5&gt;]</span></span></code></pre></div>
<p>This creates an array of 5 items but without any values. But
javascript doesn't use undefined as the default values tho. It instead
creates empty slots (holes) in the arrays but keeps given the length. So
when you copy it using the reduce method, it doesn't iterate over the
empty slots. So the newly generated array is shorter.</p>
<hr />
<h3 id="schrodingers-magic-list">Schrodinger's magic list</h3>
<p>The list we are gonna be working on is document.all which is a list
of all nodes in a document.</p>
<div class="sourceCode" id="cb8"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="bu">document</span><span class="op">.</span><span class="at">all</span> <span class="co">// &gt; HTMLAllCollection {...}</span></span></code></pre></div>
<p>Council of W3C, give me the strength to make this list disappear!!!
Boom! Shaa! Waka-Waka Boom!</p>
<div class="sourceCode" id="cb9"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">typeof</span> <span class="bu">document</span><span class="op">.</span><span class="at">all</span> <span class="co">// &gt; undefined</span></span></code></pre></div>
<p><strong><em>Be Amazed!!</em></strong></p>
<p>Go get an MRI scan because your tiny little brain just exploded!</p>
<h4 id="heres-the-big-reveal">Here's the big reveal!</h4>
<p><code>document.all</code> is a very old and deprecated api that
allowed you to iterate over all the nodes rendered to the DOM. The
typeof expression returning <code>undefined</code> was by design as a
part of deprecation of that non-standard feature. Weird, I know. But
that's just how javascript rolls.</p>
<hr />
<h3 id="are-we-infinity-yet">Are we Infinity yet?</h3>
<p>Let's take a number, <code>let x: number</code>.</p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>x <span class="op">+</span> <span class="dv">1</span> <span class="op">===</span> x<span class="op">;</span> <span class="co">// &gt;&gt; true</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>x <span class="op">+</span> <span class="dv">2</span> <span class="op">===</span> x<span class="op">;</span> <span class="co">// &gt;&gt; false</span></span></code></pre></div>
<p>“What just happened?”</p>
<p>I added 1 to x and the value didn't change! Then I added 2 to it and…
the universe… it changed.</p>
<h4 id="check-out-how-this-works">Check out how this works</h4>
<div class="sourceCode" id="cb11"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> x <span class="op">=</span> <span class="fl">1e16</span><span class="op">;</span> <span class="co">// OR 1 * Math.pow(10, 16) OR 10000000000000000</span></span></code></pre></div>
<p>This is by design. It's documented in IEEE 754-2008. When the number
is as large as this, it rounds it up to the nearest even number.</p>
<p>Ref: <a
href="https://en.wikipedia.org/wiki/IEEE_754#Rounding_rules">Rounding
rules section in IEEE 754</a></p>
<hr />
<h3
id="is-a-not-a-number-a-number-or-not-a-number-well-its-nan-of-your-business">Is
a “not a number” a number or not a number? Well, it's NaN of your
business</h3>
<div class="sourceCode" id="cb12"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">typeof</span> <span class="kw">NaN</span> <span class="op">===</span> <span class="st">&#39;number&#39;</span> <span class="co">// &gt;&gt; true</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="kw">NaN</span> <span class="op">!==</span> <span class="kw">NaN</span> <span class="co">// &gt;&gt; true</span></span></code></pre></div>
<p>Wut? ‘Not a number' is a number and ‘Not a number' is not equal to
‘Not a number'</p>
<p>Javascript is a magical language</p>
<h4 id="know-the-trick">Know the trick</h4>
<p>NaN is a numeric data type but it behaves as an identity when any
mathematical operation is applied to it.</p>
<p><em>“But why is NaN === NaN returning false?”</em></p>
<p>Because the Gods of Javascript wished so. If either side of ===
operator is NaN, the operation returns false. Thats just how it works.
Don't question it.</p>
<hr />
<h3 id="check-if-your-list-has-more-than-1-items">Check if your list has
more than 1 items</h3>
<p>A very complicated problem in programming.</p>
<p>A normie dev would go ahead and write something like</p>
<div class="sourceCode" id="cb13"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> hasAtleast2Elements <span class="op">=</span> x <span class="kw">=&gt;</span> x<span class="op">.</span><span class="at">length</span> <span class="op">&gt;=</span> <span class="dv">2</span><span class="op">;</span></span></code></pre></div>
<p>That solution is 13 characters long. In the modern world of
javascript, 13 characters is way too many characters. It is a
performance bottleneck.</p>
<p>Let's write something more optimized in size</p>
<div class="sourceCode" id="cb14"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> hasAtleast2Elements <span class="op">=</span> x <span class="kw">=&gt;</span> <span class="op">!</span><span class="pp">isNaN</span>(<span class="op">+</span>x)<span class="op">;</span></span></code></pre></div>
<p>There. 10 characters. Much better. We removed <strong>23%</strong> of
our JavaScript! Good job. Less JavaScript is good JavaScript</p>
<h4 id="the-genius-behind-this-action">The genius behind this
action</h4>
<p>We improved our load time by 23% but at what cost?! How does that
function even work? Magic? Not magic, JavaScript!</p>
<p>The + operator applied to a list returns NaN if the number of items
in the list is more than 1.</p>
<p>Why does it do that? Well, type casting. +[] is equal to
+[].toString().</p>
<p>So,</p>
<div class="sourceCode" id="cb15"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>[]<span class="op">.</span><span class="fu">toString</span>() <span class="op">===</span> <span class="st">&#39;&#39;</span> <span class="co">// &gt;&gt; +&#39;&#39; === 0</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>]<span class="op">.</span><span class="fu">toString</span>() <span class="op">===</span> <span class="st">&#39;1&#39;</span> <span class="co">// &gt;&gt; +&#39;1&#39; === 1</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span><span class="op">,</span> <span class="dv">2</span>]<span class="op">.</span><span class="fu">toString</span>() <span class="op">===</span> <span class="st">&#39;1,2&#39;</span> <span class="co">// &gt;&gt; +&#39;1,2&#39; === NaN (Cannot typecast as it is not a number)</span></span></code></pre></div>
<hr />
<hr />
<p>That's all for today! Tune in next time to watch Magnifico use magic
in production and get fired immediately.</p>
<p>Now I'm gonna make myself disappear.</p>
<p>…</p>
<p>…</p>
<p>…</p>
<p>Why is this… Just a second folks… Some technical difficul…</p>
<p><strong><em>magic man magically disappears</em></strong></p>

]]>
</description></item>
<item><guid>2019-03-15-redux-recipies</guid>
<title>Grandma&#x27;s recipes for cooking redux</title>
<link>https://ediblemonad.dev/blog/2019-03-15-redux-recipies</link>
<comments>https://ediblemonad.dev/blog/2019-03-15-redux-recipies</comments>
<pubDate>2019-03-15</pubDate>
<description>
<![CDATA[
<h1 id="grandmas-recipes-for-cooking-redux">Grandma's recipes for
cooking redux</h1>
<p>Welcome to my Grandma's Kitchen. I'm your host, the grandson. Let's
start cooking, shall we?</p>
<p>Disclaimer: Stuff referenced in this post are not my opinions, they
are straight up facts. If you disagree, you're probably right but don't
tell anyone. Reader discretion is advised.</p>
<p>For far too long have we suffered the torture of writing boilerplate
code and messy actions. Not anymore. Here are some recipes to cook redux
the way my grandma wants you to.</p>
<p>We are going to be cooking with the following ingredients today -</p>
<ul>
<li><a href="https://github.com/redux-saga/redux-saga">Redux
Saga</a></li>
<li><a href="https://github.com/phenax/redux-utils">Redux Utils</a></li>
<li><a href="https://github.com/evilsoft/crocks">Crocks</a></li>
<li><a href="https://github.com/reduxjs/reselect">Reselect</a></li>
<li><a href="https://github.com/ramda/ramda">Ramda</a> (optional. Add
according to taste)</li>
</ul>
<hr />
<h3 id="spicy-hot-action-namestypes">Spicy hot action names/types</h3>
<p>You wouldn't expect there to be any changes in the way you create
action names/types but why not? Go check your action types file. You
will find that there is a recurring pattern of the three states.
<code>ACTION_PENDING</code>, <code>ACTION_SUCCESS</code> and
<code>ACTION_FAILURE</code> (not FAIL because <code>PENDING</code>,
<code>SUCCESS</code> and <code>FAILURE</code> have the same number of
characters and my grandma likes consistency). And while we are at it we
can also learn something from the REST architecture from my grandma's
time and bring the resource/action pattern in here.</p>
<p><code>actionTypes</code> function uses the
<code>@resource/ACTION/STATE</code> convention.</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { actionTypes } <span class="im">from</span> <span class="st">&#39;@phenax/redux-utils&#39;</span><span class="op">;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> types <span class="op">=</span> <span class="fu">actionTypes</span>({</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">DISHES</span><span class="op">:</span> {</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">LIST</span><span class="op">:</span> [<span class="st">&#39;PENDING&#39;</span><span class="op">,</span> <span class="st">&#39;SUCCESS&#39;</span><span class="op">,</span> <span class="st">&#39;FAILURE&#39;</span>]<span class="op">,</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    <span class="dt">ADD</span><span class="op">:</span> [<span class="st">&#39;PENDING&#39;</span><span class="op">,</span> <span class="st">&#39;SUCCESS&#39;</span><span class="op">,</span> <span class="st">&#39;FAILURE&#39;</span>]<span class="op">,</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>  }<span class="op">,</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  <span class="dt">SESSION</span><span class="op">:</span> {</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>    <span class="dt">INIT</span><span class="op">:</span> [<span class="st">&#39;PENDING&#39;</span><span class="op">,</span> <span class="st">&#39;SUCCESS&#39;</span><span class="op">,</span> <span class="st">&#39;FAILURE&#39;</span>]<span class="op">,</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>  }<span class="op">,</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>})<span class="op">;</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>types<span class="op">.</span><span class="at">DISHES</span><span class="op">.</span><span class="at">ADD</span><span class="op">.</span><span class="at">SUCCESS</span> <span class="op">===</span> <span class="st">&#39;@dishes/ADD/SUCCESS&#39;</span><span class="op">;</span> <span class="co">// true</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="co">// Your actions will then look something like</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a><span class="fu">dispatch</span>({</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>  <span class="dt">type</span><span class="op">:</span> types<span class="op">.</span><span class="at">DISHES</span><span class="op">.</span><span class="at">ADD</span><span class="op">.</span><span class="at">_</span><span class="op">,</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>  <span class="dt">payload</span><span class="op">:</span> {</span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>    <span class="dt">name</span><span class="op">:</span> <span class="st">&#39;Chicken that tastes like paneer&#39;</span><span class="op">,</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>    <span class="dt">ingredients</span><span class="op">:</span> {</span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>      <span class="dt">chicken</span><span class="op">:</span> { <span class="dt">count</span><span class="op">:</span> <span class="dv">1</span><span class="op">,</span> <span class="dt">unit</span><span class="op">:</span> <span class="st">&#39;bird&#39;</span> }<span class="op">,</span></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>      <span class="dt">salt</span><span class="op">:</span> { <span class="dt">toTaste</span><span class="op">:</span> <span class="kw">true</span> }<span class="op">,</span></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a>      <span class="dt">pepper</span><span class="op">:</span> { <span class="dt">count</span><span class="op">:</span> <span class="dv">2</span><span class="op">,</span> <span class="dt">unit</span><span class="op">:</span> <span class="st">&#39;shakes&#39;</span> }<span class="op">,</span></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a>      <span class="dt">milk</span><span class="op">:</span> { <span class="dt">count</span><span class="op">:</span> <span class="dv">3</span><span class="op">,</span> <span class="dt">unit</span><span class="op">:</span> <span class="st">&#39;seconds of pouring&#39;</span> }<span class="op">,</span></span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a>    }<span class="op">,</span></span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a>  }<span class="op">,</span></span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a>})<span class="op">;</span></span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a><span class="co">// The underescore (`._`) is the dispatch that gets picked up by the sagas. Its a default dispatch i.e. stateless dispatch.</span></span></code></pre></div>
<hr />
<h3 id="reducer-salad">Reducer salad</h3>
<p>The three state pattern is also seen repeated a lot inside reducers.
My grandma keeps telling me “My back hurts when I scroll through long
switch-case statements”. So if you haven't guessed already, we are going
to change that too now. We have to care for the elderly.</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { createPartialReducer<span class="op">,</span> mergeReducers } <span class="im">from</span> <span class="st">&#39;@phenax/redux-utils&#39;</span><span class="op">;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> initialState <span class="op">=</span> { <span class="dt">loading</span><span class="op">:</span> <span class="kw">false</span><span class="op">,</span> <span class="dt">readyForServing</span><span class="op">:</span> <span class="kw">true</span><span class="op">,</span> <span class="dt">dishes</span><span class="op">:</span> []<span class="op">,</span> <span class="dt">error</span><span class="op">:</span> <span class="st">&quot;&quot;</span> }<span class="op">;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> getLoadingState <span class="op">=</span> state <span class="kw">=&gt;</span> ({ readyForServing }) <span class="kw">=&gt;</span> ({</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">...</span>state<span class="op">,</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>  readyForServing<span class="op">,</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  <span class="dt">loading</span><span class="op">:</span> <span class="kw">true</span><span class="op">,</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>})<span class="op">;</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> addDishReducer <span class="op">=</span> <span class="fu">createPartialReducer</span>(types<span class="op">.</span><span class="at">DISHES</span><span class="op">.</span><span class="at">ADD</span><span class="op">,</span> (state <span class="op">=</span> initialState<span class="op">,</span> action) <span class="kw">=&gt;</span> ({</span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>  <span class="dt">PENDING</span><span class="op">:</span> <span class="fu">getLoadingState</span>(state)<span class="op">,</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>  <span class="dt">SUCCESS</span><span class="op">:</span> newDish <span class="kw">=&gt;</span> ({</span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>    <span class="op">...</span>state<span class="op">,</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>    <span class="dt">readyForServing</span><span class="op">:</span> <span class="kw">true</span><span class="op">,</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a>    <span class="dt">loading</span><span class="op">:</span> <span class="kw">true</span><span class="op">,</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>    <span class="dt">dishes</span><span class="op">:</span> [<span class="op">...</span>state<span class="op">.</span><span class="at">dishes</span><span class="op">,</span> newDish]<span class="op">,</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>  })<span class="op">,</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>  <span class="dt">FAILURE</span><span class="op">:</span> e <span class="kw">=&gt;</span> ({</span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">...</span>state<span class="op">,</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>    <span class="dt">readyForServing</span><span class="op">:</span> <span class="kw">false</span><span class="op">,</span></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a>    <span class="dt">loading</span><span class="op">:</span> <span class="kw">true</span><span class="op">,</span></span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a>    <span class="dt">error</span><span class="op">:</span> e<span class="op">.</span><span class="at">message</span><span class="op">,</span></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a>  })<span class="op">,</span></span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a>}))<span class="op">;</span></span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-27"><a href="#cb2-27" aria-hidden="true" tabindex="-1"></a><span class="co">// Your regular reducer can be merged with partials</span></span>
<span id="cb2-28"><a href="#cb2-28" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> regularOldReducer <span class="op">=</span> (state <span class="op">=</span> initialState<span class="op">,</span> action) <span class="kw">=&gt;</span> {</span>
<span id="cb2-29"><a href="#cb2-29" aria-hidden="true" tabindex="-1"></a>  <span class="cf">switch</span>(action<span class="op">.</span><span class="at">type</span>) {</span>
<span id="cb2-30"><a href="#cb2-30" aria-hidden="true" tabindex="-1"></a>    <span class="cf">case</span> types<span class="op">.</span><span class="at">SOMEOTHER</span><span class="op">.</span><span class="at">ACTION</span><span class="op">.</span><span class="at">PENDING</span><span class="op">:</span></span>
<span id="cb2-31"><a href="#cb2-31" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> {</span>
<span id="cb2-32"><a href="#cb2-32" aria-hidden="true" tabindex="-1"></a>        <span class="op">...</span>state<span class="op">,</span></span>
<span id="cb2-33"><a href="#cb2-33" aria-hidden="true" tabindex="-1"></a>        <span class="dt">loading</span><span class="op">:</span> <span class="kw">true</span><span class="op">,</span></span>
<span id="cb2-34"><a href="#cb2-34" aria-hidden="true" tabindex="-1"></a>      }<span class="op">;</span></span>
<span id="cb2-35"><a href="#cb2-35" aria-hidden="true" tabindex="-1"></a>    <span class="cf">case</span> types<span class="op">.</span><span class="at">SOMEOTHER</span><span class="op">.</span><span class="at">ACTION</span><span class="op">.</span><span class="at">SUCCESS</span><span class="op">:</span></span>
<span id="cb2-36"><a href="#cb2-36" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> {</span>
<span id="cb2-37"><a href="#cb2-37" aria-hidden="true" tabindex="-1"></a>        <span class="op">...</span>state<span class="op">,</span></span>
<span id="cb2-38"><a href="#cb2-38" aria-hidden="true" tabindex="-1"></a>        <span class="dt">loading</span><span class="op">:</span> <span class="kw">false</span><span class="op">,</span></span>
<span id="cb2-39"><a href="#cb2-39" aria-hidden="true" tabindex="-1"></a>        <span class="dt">dishes</span><span class="op">:</span> []<span class="op">,</span></span>
<span id="cb2-40"><a href="#cb2-40" aria-hidden="true" tabindex="-1"></a>      }<span class="op">;</span></span>
<span id="cb2-41"><a href="#cb2-41" aria-hidden="true" tabindex="-1"></a>    <span class="cf">case</span> types<span class="op">.</span><span class="at">SOMEOTHER</span><span class="op">.</span><span class="at">ACTION</span><span class="op">.</span><span class="at">FAILURE</span><span class="op">:</span></span>
<span id="cb2-42"><a href="#cb2-42" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> {</span>
<span id="cb2-43"><a href="#cb2-43" aria-hidden="true" tabindex="-1"></a>        <span class="op">...</span>state<span class="op">,</span></span>
<span id="cb2-44"><a href="#cb2-44" aria-hidden="true" tabindex="-1"></a>        <span class="dt">loading</span><span class="op">:</span> <span class="kw">false</span><span class="op">,</span></span>
<span id="cb2-45"><a href="#cb2-45" aria-hidden="true" tabindex="-1"></a>        <span class="dt">dishes</span><span class="op">:</span> []<span class="op">,</span></span>
<span id="cb2-46"><a href="#cb2-46" aria-hidden="true" tabindex="-1"></a>        <span class="dt">error</span><span class="op">:</span> e<span class="op">.</span><span class="at">message</span><span class="op">,</span></span>
<span id="cb2-47"><a href="#cb2-47" aria-hidden="true" tabindex="-1"></a>      }<span class="op">;</span></span>
<span id="cb2-48"><a href="#cb2-48" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb2-49"><a href="#cb2-49" aria-hidden="true" tabindex="-1"></a>}<span class="op">;</span></span>
<span id="cb2-50"><a href="#cb2-50" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-51"><a href="#cb2-51" aria-hidden="true" tabindex="-1"></a><span class="im">export</span> <span class="im">default</span> <span class="fu">mergeReducers</span>(addDishReducer<span class="op">,</span> regularOldReducer)<span class="op">;</span></span></code></pre></div>
<p>The partial reducers allow you to split the reducer into smaller
functions based on the resource/action/state convention. You can also
use this to show off your rad point-free trick shots.</p>
<hr />
<h3 id="duck-promises">Duck promises</h3>
<p>There are 3 different ways to interpret name of this dish. Clue, it's
not a typo (even though it fits perfectly). Another clue, we're not
cooking a duck here. You are correct. Just duck those promises and go
with <code>Async</code> from crocks. (Not to be confused with
<code>async/await</code> which is just a prank that the C# community is
playing on us disguised as w3c draft authors). Here's how to use fetch
(or any other promise based api) and turn it into a composible,
cancellable, lazy Async task. Grandma does not approve laziness but we
will use it anyway because GOD DAMMIT, IT'S MY FREAKING COOKING SHOW!
GET OUT OF MY ROOM, GRANDMA!</p>
<p>For you, a simple made-up example of fetching with network timeout.
fetchJson is just an Async wrapper for fetch api.</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> Async <span class="im">from</span> <span class="st">&#39;crocks/Async&#39;</span><span class="op">;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { prop<span class="op">,</span> filter<span class="op">,</span> map<span class="op">,</span> either<span class="op">,</span> complement } <span class="im">from</span> <span class="st">&#39;ramda&#39;</span><span class="op">;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { fetchJson } <span class="im">from</span> <span class="st">&#39;@phenax/redux-utils/async&#39;</span><span class="op">;</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="co">// Some other api call that happens after we get the data from the user</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="co">// fetchChefInfo :: a -&gt; Async a</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> fetchChefInfo <span class="op">=</span> data <span class="kw">=&gt;</span> <span class="fu">Async</span>((rej<span class="op">,</span> res) <span class="kw">=&gt;</span> <span class="pp">setTimeout</span>(() <span class="kw">=&gt;</span> <span class="fu">res</span>(data)<span class="op">,</span> <span class="dv">700</span>))<span class="op">;</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="co">// fetchServableDishes :: Object * -&gt; Async [User]</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> fetchServableDishes <span class="op">=</span> params <span class="kw">=&gt;</span> <span class="fu">fetchJson</span>(<span class="st">&#39;/dishes&#39;</span><span class="op">,</span> params)</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">.</span><span class="fu">race</span>(Async<span class="op">.</span><span class="fu">rejectAfter</span>(<span class="dv">2000</span><span class="op">,</span> <span class="kw">new</span> <span class="bu">Error</span>(<span class="st">&#39;Request Timeout&#39;</span>)))</span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">.</span><span class="fu">map</span>(<span class="fu">prop</span>(<span class="st">&#39;dishes&#39;</span>))</span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>  <span class="op">.</span><span class="fu">map</span>(<span class="fu">compose</span>(</span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>    filter<span class="op">,</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>    complement<span class="op">,</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>    <span class="fu">either</span>(</span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a>      <span class="fu">prop</span>(<span class="st">&#39;isReady&#39;</span>)<span class="op">,</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a>      <span class="fu">prop</span>(<span class="st">&#39;isBurnt&#39;</span>)<span class="op">,</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a>    )<span class="op">,</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a>  ))<span class="op">;</span></span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> task <span class="op">=</span> <span class="fu">fetchServableDishes</span>()<span class="op">;</span></span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a><span class="co">// The request has not been sent yet (it&#39;s lazy like crazy! Thank you. Thank you.). You can keep composing and chaining stuff</span></span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a>task <span class="op">=</span> task</span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true" tabindex="-1"></a>  <span class="op">.</span><span class="fu">map</span>(<span class="fu">map</span>(decorateDish))</span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true" tabindex="-1"></a>  <span class="op">.</span><span class="fu">chain</span>(fetchChefInfo)<span class="op">;</span></span>
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-29"><a href="#cb3-29" aria-hidden="true" tabindex="-1"></a><span class="co">// And when you finally decide that you want to make the api call, you can fork it.</span></span>
<span id="cb3-30"><a href="#cb3-30" aria-hidden="true" tabindex="-1"></a><span class="co">// Nothing is executed till you call .fork</span></span>
<span id="cb3-31"><a href="#cb3-31" aria-hidden="true" tabindex="-1"></a>task<span class="op">.</span><span class="fu">fork</span>(</span>
<span id="cb3-32"><a href="#cb3-32" aria-hidden="true" tabindex="-1"></a>  e <span class="kw">=&gt;</span> <span class="bu">console</span><span class="op">.</span><span class="fu">error</span>(e)<span class="op">,</span></span>
<span id="cb3-33"><a href="#cb3-33" aria-hidden="true" tabindex="-1"></a>  activeUsers <span class="kw">=&gt;</span> {</span>
<span id="cb3-34"><a href="#cb3-34" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Do stuff</span></span>
<span id="cb3-35"><a href="#cb3-35" aria-hidden="true" tabindex="-1"></a>  }<span class="op">,</span></span>
<span id="cb3-36"><a href="#cb3-36" aria-hidden="true" tabindex="-1"></a>)<span class="op">;</span></span></code></pre></div>
<hr />
<h3 id="barbecue-sagas">Barbecue sagas</h3>
<p>Redux saga is the best way to write actions. That is a fact, not an
opinion. No need to look it up. Not going to change anything with that
but we can add a few ingredients to enhance its flavor. We are also
going to use <code>Async</code> instead of <code>Promise</code> because
my grandma believes you shouldn't make promises you can't
keep/manage.</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { put } <span class="im">from</span> <span class="st">&#39;redux-saga/effects&#39;</span><span class="op">;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { callAsync<span class="op">,</span> putResponse } <span class="im">from</span> <span class="st">&#39;@phenax/redux-utils/saga&#39;</span><span class="op">;</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="im">export</span> <span class="kw">function</span><span class="op">*</span> <span class="fu">add</span>({ payload }) {</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">yield</span> <span class="fu">put</span>({ <span class="dt">type</span><span class="op">:</span> types<span class="op">.</span><span class="at">DISHES</span><span class="op">.</span><span class="at">ADD</span><span class="op">.</span><span class="at">PENDING</span><span class="op">,</span> <span class="dt">payload</span><span class="op">:</span> {} })<span class="op">;</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> response <span class="op">=</span> <span class="kw">yield</span> <span class="fu">callAsync</span>(saveNewDish<span class="op">,</span> payload)<span class="op">;</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">yield</span> <span class="fu">putResponse</span>(types<span class="op">.</span><span class="at">DISHES</span><span class="op">.</span><span class="at">ADD</span><span class="op">,</span> response)<span class="op">;</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>}<span class="op">;</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="im">export</span> <span class="kw">function</span><span class="op">*</span> <span class="fu">list</span>({ payload }) {</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">yield</span> <span class="fu">put</span>({ <span class="dt">type</span><span class="op">:</span> types<span class="op">.</span><span class="at">DISHES</span><span class="op">.</span><span class="at">LIST</span><span class="op">.</span><span class="at">PENDING</span><span class="op">,</span> <span class="dt">payload</span><span class="op">:</span> {} })<span class="op">;</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> response <span class="op">=</span> <span class="kw">yield</span> <span class="fu">callAsync</span>(fetchServableDishes)<span class="op">;</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">yield</span> <span class="fu">putResponse</span>(types<span class="op">.</span><span class="at">DISHES</span><span class="op">.</span><span class="at">LIST</span><span class="op">,</span> response)<span class="op">;</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>}<span class="op">;</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a><span class="im">export</span> <span class="im">default</span> <span class="kw">function</span><span class="op">*</span> <span class="bu">root</span>() {</span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a>  <span class="kw">yield</span> <span class="fu">all</span>([<span class="fu">takeLatest</span>(types<span class="op">.</span><span class="at">DISHES</span><span class="op">.</span><span class="at">ADD</span><span class="op">.</span><span class="at">_</span><span class="op">,</span> add)])<span class="op">;</span></span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a>  <span class="kw">yield</span> <span class="fu">all</span>([<span class="fu">takeLatest</span>(types<span class="op">.</span><span class="at">DISHES</span><span class="op">.</span><span class="at">LIST</span><span class="op">.</span><span class="at">_</span><span class="op">,</span> list)])<span class="op">;</span></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a>}<span class="op">;</span></span></code></pre></div>
<p>Here,</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">yield</span> <span class="fu">putResponse</span>(types<span class="op">.</span><span class="at">DISHES</span><span class="op">.</span><span class="at">LIST</span><span class="op">,</span> response)<span class="op">;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="co">// is just a shorthand for</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">yield</span> <span class="fu">put</span>(response<span class="op">.</span><span class="fu">cata</span>({</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Success</span><span class="op">:</span> data <span class="kw">=&gt;</span> ({ <span class="dt">type</span><span class="op">:</span> types<span class="op">.</span><span class="at">DISHES</span><span class="op">.</span><span class="at">LIST</span><span class="op">.</span><span class="at">SUCCESS</span><span class="op">,</span> <span class="dt">payload</span><span class="op">:</span> data })<span class="op">,</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Failure</span><span class="op">:</span> error <span class="kw">=&gt;</span> ({ <span class="dt">type</span><span class="op">:</span> types<span class="op">.</span><span class="at">DISHES</span><span class="op">.</span><span class="at">LIST</span><span class="op">.</span><span class="at">FAILURE</span><span class="op">,</span> <span class="dt">payload</span><span class="op">:</span> error })<span class="op">,</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>}))<span class="op">;</span></span></code></pre></div>
<hr />
<h3 id="selector-noodles">Selector noodles</h3>
<p>Selectors allow you to derive your data from the state and memoize
the operation. We are going to use reselect for this and we're also
gonna sprinkle some ramda in there according to taste. You can use
lodash too but why would you do something like that? Ramda is to lodash
what a smart watch is to a tin-can telephone.</p>
<p>Grandma: “Back in my day, underscore was pretty popular. It was
like…”.</p>
<p>Yeah grandma, we get it, you're old. Now shut up and let me show
these people some selector action.</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { createSelector } <span class="im">from</span> <span class="st">&quot;reselect&quot;</span><span class="op">;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { pathOr<span class="op">,</span> prop<span class="op">,</span> __<span class="op">,</span> map } <span class="im">from</span> <span class="st">&#39;ramda&#39;</span><span class="op">;</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="co">// selectBurntDishes :: { dishes :: { dishIds :: [String], items :: Object Profile } } -&gt; [String]</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="im">export</span> <span class="kw">const</span> selectBurntDishes <span class="op">=</span> <span class="fu">createSelector</span>(</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pathOr</span>({}<span class="op">,</span> [<span class="st">&#39;dishes&#39;</span><span class="op">,</span> <span class="st">&#39;items&#39;</span>])<span class="op">,</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pathOr</span>([]<span class="op">,</span> [<span class="st">&#39;dishes&#39;</span><span class="op">,</span> <span class="st">&#39;dishIds&#39;</span>])<span class="op">,</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>  (items<span class="op">,</span> dishIds) <span class="kw">=&gt;</span> dishIds<span class="op">.</span><span class="fu">filter</span>(<span class="fu">compose</span>(</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>    <span class="fu">prop</span>(<span class="st">&#39;isBurnt&#39;</span>)<span class="op">,</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>    <span class="fu">map</span>(<span class="fu">prop</span>(__<span class="op">,</span> items))<span class="op">,</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>  ))<span class="op">,</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>)<span class="op">;</span></span></code></pre></div>
<p>Now you can use it anywhere…</p>
<p>In you component's mapStateToProps,</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> mapStateToProps <span class="op">=</span> state <span class="kw">=&gt;</span> ({</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">burntDishes</span><span class="op">:</span> <span class="fu">selectBurntDishes</span>(state)<span class="op">,</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>})<span class="op">;</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="im">export</span> <span class="im">default</span> <span class="fu">connect</span>(mapStateToProps)(ListBurntDishes)<span class="op">;</span></span></code></pre></div>
<p>In your sagas,</p>
<div class="sourceCode" id="cb8"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">function</span><span class="op">*</span> <span class="fu">mySaga</span>() {</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> burntDishes <span class="op">=</span> <span class="kw">yield</span> <span class="fu">select</span>(selectBurntDishes)<span class="op">;</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Do stuff with those ids</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>Doesn't that look pretty? If you're new to the point-free way, you
may feel like you just watched a french movie without subtitles but
trust me, this is worth the confusing first few days.</p>
<hr />
<h3 id="conclusion">Conclusion</h3>
<p>Old ideas and opinions are what new ones are born from. Grandma's
recipes were great and they've come out of experience that doesn't mean
we have to keep making the same thing a billion times. Small (and
sometimes large) migrations are a good thing.</p>
<p>So let's summarise. What did we learn today?</p>
<ul>
<li>Use grandma's favorite convention of
<code>@resource/ACTION/STATE</code> for your action types</li>
<li>The elderly hate long switch case statements</li>
<li>Duck promises because <code>Async</code> rocks!</li>
<li>Sagas are the freakin best!!</li>
<li>Memoize those selectors for a better tomorrow</li>
</ul>
<p>These are all solutions to the small yet annoying inconveniences that
I ran into while working on a personal project of mine. I'm collecting
all of the tiny helpers over at <a
href="https://github.com/phenax/redux-utils">@phenax/redux-utils</a>.
The project is not done yet so the library will be getting more updates.
PRs are welcome!!</p>
<p>Hope these ideas help you write some tasty code.</p>

]]>
</description></item>
<item><guid>2019-03-14-sum-types</guid>
<title>Functional JS - Sum Types In JavaScript</title>
<link>https://ediblemonad.dev/blog/2019-03-14-sum-types</link>
<comments>https://ediblemonad.dev/blog/2019-03-14-sum-types</comments>
<pubDate>2019-03-14</pubDate>
<description>
<![CDATA[
<h1 id="functional-js---sum-types-in-javascript">Functional JS - Sum
Types In JavaScript</h1>
<p>JavaScript has a very bad reputation in most developer communities.
So much so that, “Writing cleaner and safer JavaScript…” in the title
may already seem a bit redundant to most readers. A lot of that has to
do with loose typing, invalid values and the horrible chain of ternary
expressions or heaven forbid, if statements to handle them. With
JavaScript, all functions run on the concept of “pretend what you are
getting is what you asked for”. If the value is not valid for the kind
of operation you are running on it, well, too bad. To save yourself from
this, you can write run-time validations, add type-checks, etc but the
core of the problem is till left largely unsolved.</p>
<hr />
<h3 id="lets-learn-from-haskell">Let’s learn from Haskell</h3>
<p>Functional programming languages like Haskell have a clear solution
for this. Sum Types! Sum Type (or Tagged Union) is an Algebraic Data
Type which describes values that can take on several different types.
Popular examples in haskell are the Maybe monad (for handling the
validity of values) and the Either monad (for error handling).</p>
<p>Don’t worry. Maybe, I don’t know anything about monads Either (see
what I did there?). All we need to know is that a Sum Type is a has
multiple named constructors.</p>
<p>In Haskell, a Sum type looks something like this -</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">MetalGenre</span> <span class="ot">=</span> <span class="dt">ProgMetal</span> <span class="op">|</span> <span class="dt">DeathCore</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ot">scream ::</span> <span class="dt">MetalGenre</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>scream genre <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="kw">case</span> genre <span class="kw">of</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">ProgMetal</span> <span class="ot">-&gt;</span> <span class="st">&quot;Oh!&quot;</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  <span class="dt">DeathCore</span> <span class="ot">-&gt;</span> <span class="st">&quot;BleaAaAHHH!!&quot;</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span>()</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> scream <span class="dt">ProgMetal</span></span></code></pre></div>
<p>Here, MetalGenre is the type and ProgMetal, DeathCore are
constructors of that type.</p>
<p>A really popular and useful example of a Sum type in the functional
world is the Maybe type. In Haskell, Maybe is a monad that wraps a value
and helps you make sure that invalid values are not acted upon, thus
allowing you to write safer functions.</p>
<p>This is what Maybe’s definition looks like in Haskell -</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Maybe</span> <span class="ot">=</span> <span class="dt">Just</span> a <span class="op">|</span> <span class="dt">Nothing</span></span></code></pre></div>
<p>Now here, all valid values will be wrapped in a Just and all invalid
values will be wrapped in a Nothing. This way, we can handle invalid
values in a clean and elegant way and be sure of the fact that the
function is only called for the valid values.</p>
<p>You might be thinking, “But isn’t this only possible because Haskell
is a statically typed beauty and JavaScript is the spawn of satan?”.
Maybe it isn’t. (The joke’s getting old now)</p>
<hr />
<h3 id="enumfp">EnumFP</h3>
<p>Shameless self-plug alert!</p>
<p>I have a library to help with that! (Said every JavaScript developer
ever).</p>
<p><a href="https://github.com/phenax/enum-fp">EnumFP</a> (PRs
welcome)</p>
<p>EnumFP is a simple and light-weight way to create Sum types in
JavaScript. Inspired by the awesomeness of Haskell, the library is
written with safety in mind.</p>
<p>This is what the metal genre example would look like with EnumFP.</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> MetalGenre <span class="op">=</span> <span class="fu">Enum</span>([<span class="st">&#39;ProgMetal&#39;</span><span class="op">,</span> <span class="st">&#39;DeathCore&#39;</span>])</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> scream <span class="op">=</span> <span class="fu">compose</span>(<span class="bu">console</span><span class="op">.</span><span class="fu">log</span><span class="op">,</span> MetalGenre<span class="op">.</span><span class="fu">cata</span>({</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">ProgMetal</span><span class="op">:</span> () <span class="kw">=&gt;</span> <span class="st">&quot;Oh!&quot;</span><span class="op">,</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">DeathCore</span><span class="op">:</span> () <span class="kw">=&gt;</span> <span class="st">&quot;BleaAaAHHH!!&quot;</span><span class="op">,</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>}))<span class="op">;</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="fu">scream</span>(MetalGenre<span class="op">.</span><span class="fu">ProgMetal</span>())<span class="op">;</span></span></code></pre></div>
<hr />
<h3 id="maybe-maybe">Maybe, maybe?</h3>
<p>The concept of what a Maybe does is more important than the
implementation itself. Containing a value in a way that allows you to
perform a set of operations on the container and not worry about the
validity of the input is what Maybe is about.</p>
<p>You can implement a simple Maybe and a couple of utility functions
using EnumFP. EnumFP also allows you to add argument descriptions. This
example uses the caseOf function which is like match but for partial
application).</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> Maybe <span class="op">=</span> <span class="fu">Enum</span>({ <span class="dt">Just</span><span class="op">:</span> [<span class="st">&#39;value&#39;</span>]<span class="op">,</span> <span class="dt">Nothing</span><span class="op">:</span> [] })<span class="op">;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="co">// fmap :: (a -&gt; b) -&gt; Maybe a -&gt; Maybe b</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> fmap <span class="op">=</span> fn <span class="kw">=&gt;</span> Maybe<span class="op">.</span><span class="fu">cata</span>({</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Just</span><span class="op">:</span> <span class="fu">compose</span>(Maybe<span class="op">.</span><span class="at">Just</span><span class="op">,</span> fn)<span class="op">,</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Nothing</span><span class="op">:</span> Maybe<span class="op">.</span><span class="at">Nothing</span><span class="op">,</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>})<span class="op">;</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="co">// mjoin :: Maybe Maybe a -&gt; Maybe a</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> mjoin <span class="op">=</span> Maybe<span class="op">.</span><span class="fu">cata</span>({</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Just</span><span class="op">:</span> x <span class="kw">=&gt;</span> x<span class="op">,</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Nothing</span><span class="op">:</span> Maybe<span class="op">.</span><span class="at">Nothing</span><span class="op">,</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>})<span class="op">;</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a><span class="co">// chain :: (a -&gt; Maybe b) -&gt; Maybe a -&gt; Maybe b</span></span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> chain <span class="op">=</span> fn <span class="kw">=&gt;</span> <span class="fu">compose</span>(mjoin<span class="op">,</span> <span class="fu">fmap</span>(fn))<span class="op">;</span></span></code></pre></div>
<p>Here,</p>
<p><strong>fmap</strong> returns a new Maybe and runs the function over
the value inside, in case of Just and ignores a Nothing. (Like
Array.prototype.map)</p>
<p><strong>mjoin</strong> unwraps a given nested Maybe. Because many
monads like Maybe, are agnostic about the value inside, you can put the
monad inside another monad (That’s what shesaid) (Like
Array.prototype.flatten)</p>
<p><strong>chain</strong> maps over the Maybe and then flattens the
resulting nested Maybe. (Like Array.prototype.flatMap).</p>
<p>Let’s use this and write a function that accepts a User instance and
gives you the first name without throwing an error for invalid user or
invalid name.</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co">// head :: [a] -&gt; Maybe a</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> head <span class="op">=</span> arr <span class="kw">=&gt;</span> (arr<span class="op">.</span><span class="at">length</span> <span class="op">?</span> Maybe<span class="op">.</span><span class="fu">Just</span>(arr[<span class="dv">0</span>]) <span class="op">:</span> Maybe<span class="op">.</span><span class="fu">Nothing</span>())<span class="op">;</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="co">// prop :: String -&gt; Object a -&gt; Maybe a</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> prop <span class="op">=</span> key <span class="kw">=&gt;</span> obj <span class="kw">=&gt;</span> key <span class="kw">in</span> obj <span class="op">?</span> Maybe<span class="op">.</span><span class="fu">Just</span>(obj[key]) <span class="op">:</span> Maybe<span class="op">.</span><span class="fu">Nothing</span>()<span class="op">;</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="co">// trim :: String -&gt; String</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> trim <span class="op">=</span> str <span class="kw">=&gt;</span> str<span class="op">.</span><span class="fu">trim</span>()<span class="op">;</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="co">// split :: String -&gt; String -&gt; [String]</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> split <span class="op">=</span> seperator <span class="kw">=&gt;</span> str <span class="kw">=&gt;</span> str<span class="op">.</span><span class="fu">split</span>(seperator)<span class="op">;</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="co">// safeUser :: User -&gt; Maybe User</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> safeUser <span class="op">=</span> user <span class="kw">=&gt;</span> <span class="fu">isUserValid</span>(user) <span class="op">?</span> Maybe<span class="op">.</span><span class="fu">Just</span>(user) <span class="op">:</span> Maybe<span class="op">.</span><span class="fu">Nothing</span>()<span class="op">;</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a><span class="co">// getFirstName :: User -&gt; Maybe String</span></span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> getFirstName <span class="op">=</span> <span class="fu">compose</span>(</span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a>    <span class="fu">chain</span>(head)<span class="op">,</span> <span class="co">// Maybe [String] -&gt; Maybe String</span></span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a>    <span class="fu">fmap</span>(<span class="fu">split</span>(<span class="st">&#39; &#39;</span>))<span class="op">,</span> <span class="co">// Maybe String -&gt; Maybe [String]</span></span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a>    <span class="fu">fmap</span>(trim)<span class="op">,</span> <span class="co">// Maybe String -&gt; Maybe String</span></span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a>    <span class="fu">chain</span>(<span class="fu">prop</span>(<span class="st">&#39;name&#39;</span>))<span class="op">,</span> <span class="co">// Maybe User -&gt; Maybe String</span></span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a>    safeUser<span class="op">,</span> <span class="co">// User -&gt; Maybe User</span></span>
<span id="cb5-23"><a href="#cb5-23" aria-hidden="true" tabindex="-1"></a>)<span class="op">;</span></span>
<span id="cb5-24"><a href="#cb5-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-25"><a href="#cb5-25" aria-hidden="true" tabindex="-1"></a>Maybe<span class="op">.</span><span class="fu">match</span>(<span class="fu">getFirstName</span>(user)<span class="op">,</span> {</span>
<span id="cb5-26"><a href="#cb5-26" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Just</span><span class="op">:</span> name <span class="kw">=&gt;</span> <span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(<span class="st">&#39;My name is&#39;</span><span class="op">,</span> name)<span class="op">,</span></span>
<span id="cb5-27"><a href="#cb5-27" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Nothing</span><span class="op">:</span> () <span class="kw">=&gt;</span> <span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(<span class="st">&#39;Whats in a name?&#39;</span>)<span class="op">,</span></span>
<span id="cb5-28"><a href="#cb5-28" aria-hidden="true" tabindex="-1"></a>})<span class="op">;</span></span></code></pre></div>
<p>In the example above, we first convert the user to a safe user by
wrapping it in a Maybe. Then we get the user’s name using the prop
function. The prop and head functions here, instead of returning the
value, wraps the value in a Maybe. This is why to map it and then unwrap
it, we use chain instead of fmap.</p>
<hr />
<h3 id="working-with-react">Working with React</h3>
<p>Yes, EnumFP works well with react! (Jumping from one over-populated
community to the next).</p>
<p>With the new react hooks being introduced in 16.8, it would be a sin
not to mention it here. EnumFP ships with a useReducer hook which is a
simple wrapper around react’s useReducer.</p>
<p>Don’t want to upgrade to 16.8? Do you still watch reruns of Seinfeld?
Want to wait for your grand-children to help you with the upgrade… and…
walking?</p>
<p>No worries. There’s an HOC available as well.</p>
<p>You can find out more about integrations with react here.</p>
<p>And this is not limited to just component state tho. You can use Sum
Types to work with any kind of enumerable state values. From handling
Success, Pending and Failure states for any action to containing values
based on it’s type or validity. Sum Types are here to clean up all of
that.</p>
<hr />
<h3 id="conclusion">Conclusion</h3>
<p>This is just the tip of the iceberg. There are a lot more of these
amazing ideas hidden in the world of functional programming, waiting to
move to other languages. Being a part of the JavaScript community for a
while has made me realise that it’s not all bad. What we lack in
language features and standard library, we make up for in the variety of
libraries just an npm install away, and the strong community constantly
working towards “Making JS great again”. So let’s build a wall together
between us and bad code. Covfefe.</p>

]]>
</description></item>
<item><guid>2026-10-04-it-resonates-with-me</guid>
<title>It resonates with me</title>
<link>https://ediblemonad.dev/games/2026-10-04-it-resonates-with-me</link>
<comments>https://ediblemonad.dev/games/2026-10-04-it-resonates-with-me</comments>
<pubDate>2026-10-04</pubDate>
<description>
<![CDATA[
<h1 id="it-resonates-with-me">It resonates with me</h1>
<p>Yep. No doubt about it. I love another remedy game. Who would've
thought, Control: resonant is brilliant. How creative they were in
exploring the Jesse, Dylan relationship. How they explored everything
the set up in Control about their childhood, Dylan's time in
containtment, etc. How deserved the transition feels from Dylan being
hated by everyone for the things he did in Control, to gaining the
respect of everyone at FBC. They humanized him the right way with guilt
weighing him despite the fact he wasn't in "control" of his actions in
Control.</p>
<p>The world they set up feels very <em>real</em> despite the absurdity
of that statement. They've poured so much detail into every concept that
I felt guilty traversing throught it quickly because I didn't get to pay
enough attention.</p>
<p>And don't get me started on the gameplay. Smooth traversal like the
original Control. Much more difficult than control but thats only a
motivation to spend time with the upgrades and exploring more side
quests. A decent variety of memorable bosses too. Chefs kiss for
striking the right balance. Although I did cheat a couple of times by
using the accessibility settings to increase damage a bit.</p>
<p>The only complain, the god damn taxi disappointment. Amazing build up
and really fun puzzles but the ending of the taxi quest was so damn
unsatisfying. Nitpick considering everything else the game gets
absolutely right.</p>
<p>Another hit as expected. This Sam Lake guy and his team know what
they're doing. More please of this.</p>

]]>
</description></item>
<item><guid>2026-06-27-gta6-has-got-your-balls</guid>
<title>GTA6 has got your balls</title>
<link>https://ediblemonad.dev/games/2026-06-27-gta6-has-got-your-balls</link>
<comments>https://ediblemonad.dev/games/2026-06-27-gta6-has-got-your-balls</comments>
<pubDate>2026-06-27</pubDate>
<description>
<![CDATA[
<h1 id="gta6-has-got-your-balls">GTA6 has got your balls</h1>
<p>GTA6 can spit in your mouth, fuck your wife, kill your dog and you'll
still pay that $100 price tag on release. Rockstar could've priced it at
the steam machine price and people would complain less.</p>
<p>We're all just weak, pathetic consumers waiting to suckle at the
bosom of Rockstar. The best we can do in the form of a protest is to
wait for a sale but you can't resist, can you?</p>
<p>At this point, I truely wish, the game sucks and people stop playing
it after a week but a man can only dream.</p>

]]>
</description></item>
<item><guid>2026-05-27-remedy-is-the-remedy</guid>
<title>Remedy is the remedy</title>
<link>https://ediblemonad.dev/games/2026-05-27-remedy-is-the-remedy</link>
<comments>https://ediblemonad.dev/games/2026-05-27-remedy-is-the-remedy</comments>
<pubDate>2026-05-27</pubDate>
<description>
<![CDATA[
<h1 id="remedy-is-the-remedy">Remedy is the remedy</h1>
<p>Going to fan boy this one because I love every single remedy game
that has come out so far (except firebreak). They make truly original
and creative... uh calling them games feels wrong. Tempted to call them
"interactive cinematic experiences" at the cost of sounding like an
asshole.</p>
<ul>
<li>Control has a fantastic story and is extremely fun to play.</li>
<li>Alan wake 2 was a huge improvement over alan wake 1 (and american
nightmare) which was my favorite game before the sequel came out.</li>
<li>Quantum break was also fun to play and watch (because it's a game
with a TV show embedded within it).</li>
<li>Old max payne games are amazing too and still fun to play even with
it's stiff, tiny bit outdated controls.</li>
</ul>
<p>This is what remedy does best and why I like them. Those finnish
bastards make amazing story-driven games and take creative risks to make
their work more interesting. Unlike activision's (treyarch, infinity
ward, sledgehammer, etc included) creatively bankrupt and completely
hollow almost-yearly call of duty releases, remedy consistently produces
quality games. You can say "apples to oranges" but I say "fruit to
fruit". Need a little bit of this in every team in the world building
things. Not everything needs to be done with the goal of feeding profit
piggy.</p>
<p>Have fun with it. Make interesting things.</p>

]]>
</description></item></channel></rss>