From b0f27dabe069d2d0ad1829ce8edd80631151521b Mon Sep 17 00:00:00 2001 From: z3rOR0ne Date: Mon, 2 Sep 2024 07:51:04 -0700 Subject: [PATCH] :memo: Made sub to jakuba blog --- .config/newsboat/my_urls | 2 + .config/newsboat/rss/jakuba_blog.xml | 7901 ++++++++++++++++++++++++++ 2 files changed, 7903 insertions(+) create mode 100644 .config/newsboat/rss/jakuba_blog.xml diff --git a/.config/newsboat/my_urls b/.config/newsboat/my_urls index 37e66b8e..898f10ce 100644 --- a/.config/newsboat/my_urls +++ b/.config/newsboat/my_urls @@ -73,3 +73,5 @@ file://./rss/jlwagner.php file://./rss/wagslane.xml file://./rss/css-irl.info.xml file://./rss/russell_cohen.xml +file://./rss/jakuba_blog.xml + diff --git a/.config/newsboat/rss/jakuba_blog.xml b/.config/newsboat/rss/jakuba_blog.xml new file mode 100644 index 00000000..9db5d54d --- /dev/null +++ b/.config/newsboat/rss/jakuba_blog.xml @@ -0,0 +1,7901 @@ + + + Jakub Arnold's Blog + https://blog.jakuba.net/ + Recent content on Jakub Arnold's Blog + Hugo -- gohugo.io + en-us + Sat, 09 May 2020 10:00:00 +0200 + + + + + + requestAnimationFrame and useEffect vs useLayoutEffect + https://blog.jakuba.net/request-animation-frame-and-use-effect-vs-use-layout-effect/ + Sat, 09 May 2020 10:00:00 +0200 + + https://blog.jakuba.net/request-animation-frame-and-use-effect-vs-use-layout-effect/ + <p>While trying to implement an animated number counter I stumbled upon an interesting issue with <code>useEffect</code> and <code>requestAnimationFrame</code> not playing together nicely that lead down a rabbit hole of confusion, but lucky for me I wasn&rsquo;t the first one to stumble upon this, and <a href="https://github.com/streamich/react-use">react-use</a> actually has resolved this exact issue in their <a href="https://github.com/streamich/react-use/blob/master/docs/useRaf.md"><code>useRaf</code> hook</a>. This post is a short explanation of the problem, and why <code>useLayoutEffect</code> fixes it.</p> +<h2 id="useeffect"><code>useEffect</code></h2> +<p>The <code>useEffect</code> hook is a useful new addition since React 16.8 that allows us to access lifecycle methods in functional components. It can act as <code>componentDidMount</code>, <code>componentDidUpdate</code> and <code>componentWillUnmount</code> while keeping the logic neatly in one place. Let&rsquo;s quickly go over the few different use cases.</p> +<p>Running code after each render:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> Counter<span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> <span style="color:#eceff4">[</span>counter<span style="color:#eceff4">,</span> setCounter<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> useState<span style="color:#eceff4">(</span><span style="color:#b48ead">0</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> useEffect<span style="color:#eceff4">(()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">document</span><span style="color:#eceff4">.</span>title <span style="color:#81a1c1">=</span> <span style="color:#a3be8c">`Counter: </span><span style="color:#a3be8c">${</span>counter<span style="color:#a3be8c">}</span><span style="color:#a3be8c">`</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">})</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">(</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span>button onClick<span style="color:#81a1c1">=</span><span style="color:#eceff4">{()</span> <span style="color:#eceff4">=&gt;</span> setCounter<span style="color:#eceff4">(</span>counter <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)}</span><span style="color:#81a1c1">&gt;</span> +</span></span><span style="display:flex;"><span> Clicked <span style="color:#eceff4">{</span>counter<span style="color:#eceff4">}</span> times +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span><span style="color:#bf616a">/button&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>While on some level this acts as <code>componentDidMount</code> and <code>componentDidUpdate</code>, what it really says is <em>queue this function to run on each render</em>. As a quick side note, you might be tempted to write the arrow function without braces like this (it might be more tempting with something else than an assignment, such as a function call):</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>useEffect<span style="color:#eceff4">(()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">document</span><span style="color:#eceff4">.</span>title <span style="color:#81a1c1">=</span> <span style="color:#a3be8c">`Counter: </span><span style="color:#a3be8c">${</span>counter<span style="color:#a3be8c">}</span><span style="color:#a3be8c">`</span><span style="color:#eceff4">))</span> +</span></span></code></pre></div><p>but if you try it React will crash with <code>TypeError: destroy is not a function</code>. This might be surprising at first, but the difference is the arrow function is now actually returning the value of the assignment, that is the string <code>Counter: ${counter}</code>. In order for <code>useEffect</code> to also handle cleanup (and be able to replace <code>componentWillUnmount</code>), it has a mechanism for the user to provide a cleanup function. This is actually what we did by accident, because the cleanup function is to be returned from the <code>effect</code>. But this shorter arrow function syntax is equivalent to writing the following:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>useEffect<span style="color:#eceff4">(()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">document</span><span style="color:#eceff4">.</span>title <span style="color:#81a1c1">=</span> <span style="color:#a3be8c">`Counter: </span><span style="color:#a3be8c">${</span>counter<span style="color:#a3be8c">}</span><span style="color:#a3be8c">`</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">})</span> +</span></span></code></pre></div><p>Now it should be more clear why react complains. It expects the return value to either be <code>undefined</code>, in which case it doesn&rsquo;t do any cleanup, or a <code>function</code> which can be called. But we&rsquo;re returning a string, which is not <code>undefined</code>, and React will crash when it tries to call it.</p> +<h3 id="useeffect-cleanup"><code>useEffect</code> cleanup</h3> +<p>Our previous example didn&rsquo;t really have any need for cleanup. We&rsquo;ll switch to using <code>setInterval</code> to create an auto-incrementing <code>counter</code> where we can also control the speed at which it increments.</p> +<p>Let&rsquo;s start with a basic structure that is buggy and we&rsquo;ll incrementally fix it. We&rsquo;ll add a second state variable <code>speed</code> which will control the <code>timeout</code> parameter of a <code>setInterval</code>. We&rsquo;ll also add two buttons to control the <code>speed</code> of the timer.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> Counter<span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> <span style="color:#eceff4">[</span>counter<span style="color:#eceff4">,</span> setCounter<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> useState<span style="color:#eceff4">(</span><span style="color:#b48ead">0</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> <span style="color:#eceff4">[</span>speed<span style="color:#eceff4">,</span> setSpeed<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> useState<span style="color:#eceff4">(</span><span style="color:#b48ead">1000</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> useEffect<span style="color:#eceff4">(()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> setInterval<span style="color:#eceff4">(()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Similarly to `this.setState` in class components, `setCounter` +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// can accept a function that takes in the current value and +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// returns a new value +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> setCounter<span style="color:#eceff4">(</span>x <span style="color:#eceff4">=&gt;</span> x <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">},</span> speed<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">})</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">(</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span>p<span style="color:#81a1c1">&gt;</span> +</span></span><span style="display:flex;"><span> Counter<span style="color:#81a1c1">:</span> <span style="color:#eceff4">{</span>counter<span style="color:#eceff4">}</span> <span style="color:#eceff4">...</span> Speed<span style="color:#81a1c1">:</span> <span style="color:#eceff4">{</span>speed<span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span>button onClick<span style="color:#81a1c1">=</span><span style="color:#eceff4">{()</span> <span style="color:#eceff4">=&gt;</span> setSpeed<span style="color:#eceff4">(</span>speed <span style="color:#81a1c1">+</span> <span style="color:#b48ead">100</span><span style="color:#eceff4">)}</span><span style="color:#81a1c1">&gt;+&lt;</span><span style="color:#bf616a">/button&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">{</span><span style="color:#616e87;font-style:italic">/* The `Math.max` is here simply so we don&#39;t set the speed to `0` */</span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span>button onClick<span style="color:#81a1c1">=</span><span style="color:#eceff4">{()</span> <span style="color:#eceff4">=&gt;</span> setSpeed<span style="color:#eceff4">(</span><span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>max<span style="color:#eceff4">(</span><span style="color:#b48ead">100</span><span style="color:#eceff4">,</span> speed <span style="color:#81a1c1">-</span> <span style="color:#b48ead">100</span><span style="color:#eceff4">))}</span><span style="color:#81a1c1">&gt;-&lt;</span><span style="color:#bf616a">/button&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span><span style="color:#bf616a">/p&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>If you were to run this code you&rsquo;ll see the issue very quickly (<a href="https://codesandbox.io/s/patient-http-qm0o1">you can try it here</a>, but be careful, it gets very laggy very quickly). The timer doesn&rsquo;t increment by <code>1</code> every second. It increments by <code>1</code> the first second, then by <code>2</code>, then by <code>3</code>, then by <code>4</code>, and so on. This is because by default <code>useEffect</code> will run on every single render, and we&rsquo;re only ever setting new intervals, we&rsquo;re not clearing the old ones.</p> +<p>A quick fix would be to return a cleanup function:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>useEffect<span style="color:#eceff4">(()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> timerId <span style="color:#81a1c1">=</span> setInterval<span style="color:#eceff4">(()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> setCounter<span style="color:#eceff4">(</span>x <span style="color:#eceff4">=&gt;</span> x <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">},</span> speed<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">()</span> <span style="color:#eceff4">=&gt;</span> clearInterval<span style="color:#eceff4">(</span>timerId<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">})</span> +</span></span></code></pre></div><p>But this is not ideal as well. Each time the <code>setInterval</code> ticks, it will call <code>setCounter</code>, which in turn causes the component to re-render. But our <code>useEffect</code> also runs on each render, which means the first tick of the timer will cause a re-render which in turn calls <code>useEffect</code>, which clears the first interval, and sets a new one. While the code seemingly does what it&rsquo;s supposed to, it&rsquo;s clearly not ideal to clear the interval on each render. We really only need to change it when <code>speed</code> changes. This is why <code>useEffect</code> has a second argument for a list of <em>dependencies</em>. Here&rsquo;s the complete component:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> Counter<span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> <span style="color:#eceff4">[</span>counter<span style="color:#eceff4">,</span> setCounter<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> useState<span style="color:#eceff4">(</span><span style="color:#b48ead">0</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> <span style="color:#eceff4">[</span>speed<span style="color:#eceff4">,</span> setSpeed<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> useState<span style="color:#eceff4">(</span><span style="color:#b48ead">1000</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> useEffect<span style="color:#eceff4">(()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;Setting up a new interval&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> timerId <span style="color:#81a1c1">=</span> setInterval<span style="color:#eceff4">(()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> setCounter<span style="color:#eceff4">(</span>x <span style="color:#eceff4">=&gt;</span> x <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">},</span> speed<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">()</span> <span style="color:#eceff4">=&gt;</span> clearInterval<span style="color:#eceff4">(</span>timerId<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">},</span> <span style="color:#eceff4">[</span>speed<span style="color:#eceff4">])</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">(</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span>p<span style="color:#81a1c1">&gt;</span> +</span></span><span style="display:flex;"><span> Counter<span style="color:#81a1c1">:</span> <span style="color:#eceff4">{</span>counter<span style="color:#eceff4">}</span> <span style="color:#eceff4">...</span> Speed<span style="color:#81a1c1">:</span> <span style="color:#eceff4">{</span>speed<span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span>button onClick<span style="color:#81a1c1">=</span><span style="color:#eceff4">{()</span> <span style="color:#eceff4">=&gt;</span> setSpeed<span style="color:#eceff4">(</span>speed <span style="color:#81a1c1">+</span> <span style="color:#b48ead">100</span><span style="color:#eceff4">)}</span><span style="color:#81a1c1">&gt;+&lt;</span><span style="color:#bf616a">/button&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">{</span><span style="color:#616e87;font-style:italic">/* The `Math.max` is here simply so we don&#39;t set the speed to `0` */</span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span>button onClick<span style="color:#81a1c1">=</span><span style="color:#eceff4">{()</span> <span style="color:#eceff4">=&gt;</span> setSpeed<span style="color:#eceff4">(</span><span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>max<span style="color:#eceff4">(</span><span style="color:#b48ead">100</span><span style="color:#eceff4">,</span> speed <span style="color:#81a1c1">-</span> <span style="color:#b48ead">100</span><span style="color:#eceff4">))}</span><span style="color:#81a1c1">&gt;-&lt;</span><span style="color:#bf616a">/button&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span><span style="color:#bf616a">/p&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p><a href="https://codesandbox.io/s/modest-water-pyd8k?file=/src/App.js">You can see it in action here</a>.</p> +<p>I&rsquo;ve also added a <code>console.log</code> to make it clear when the new <code>setInterval</code> is being set.</p> +<blockquote> +<p>It is extremely important to make a small note about closures here. If we were to touch <code>counter</code> (for example <code>setCounter(counter + 1)</code>) inside the <code>setInterval</code> callback instead of passing in <code>x =&gt; x + 1</code> then the closure would actually hold onto the variable <code>counter</code> at the time of its creation, and not get updated with the new value until <code>speed</code> changes (at which point the closure is re-created). We could potentially fix this by specifying <code>[counter, speed]</code> as deps, but that would be essentially re-creating the previous case where the interval only ever runs once.</p> +</blockquote> +<p>By specifying <code>[speed]</code> as the dependency of our effect we can control when it gets re-run. This is similar to diffing <code>props</code> within <code>componentDidUpdate</code>, but React will do that automatically for us.</p> +<p>If we didn&rsquo;t want to control the <code>speed</code>, we could simply pass in <code>[]</code> as an empty list of dependencies, which would make the <code>useEffect</code> equivalent to <code>componentDidMount</code> and not be affected by re-renders.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>useEffect<span style="color:#eceff4">(()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> timerId <span style="color:#81a1c1">=</span> setInterval<span style="color:#eceff4">(()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> setCounter<span style="color:#eceff4">(</span>x <span style="color:#eceff4">=&gt;</span> x <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">},</span> speed<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">()</span> <span style="color:#eceff4">=&gt;</span> clearInterval<span style="color:#eceff4">(</span>timerId<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">},</span> <span style="color:#eceff4">[])</span> +</span></span></code></pre></div><p>But since we care about controlling the speed, we have to leave out this option.</p> +<h3 id="pausing-and-timing-issues">pausing and timing issues</h3> +<p>We&rsquo;ll modify our example a little bit to add a Pause/Resume controls instead of controlling the speed, as this is where I initially ran into the issue with <code>requestAnimationFrame</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> Counter<span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> <span style="color:#eceff4">[</span>counter<span style="color:#eceff4">,</span> setCounter<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> useState<span style="color:#eceff4">(</span><span style="color:#b48ead">0</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> <span style="color:#eceff4">[</span>isPaused<span style="color:#eceff4">,</span> setIsPaused<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> useState<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">true</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> useEffect<span style="color:#eceff4">(()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">!</span>isPaused<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> timerId <span style="color:#81a1c1">=</span> setInterval<span style="color:#eceff4">(()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> setCounter<span style="color:#eceff4">(</span>x <span style="color:#eceff4">=&gt;</span> x <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">},</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">()</span> <span style="color:#eceff4">=&gt;</span> clearInterval<span style="color:#eceff4">(</span>timerId<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">},</span> <span style="color:#eceff4">[</span>isPaused<span style="color:#eceff4">])</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">(</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span>p<span style="color:#81a1c1">&gt;</span> +</span></span><span style="display:flex;"><span> Counter<span style="color:#81a1c1">:</span> <span style="color:#eceff4">{</span>counter<span style="color:#eceff4">}</span> <span style="color:#eceff4">...{</span><span style="color:#a3be8c">&#34; &#34;</span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span>button onClick<span style="color:#81a1c1">=</span><span style="color:#eceff4">{()</span> <span style="color:#eceff4">=&gt;</span> setIsPaused<span style="color:#eceff4">(</span><span style="color:#81a1c1">!</span>isPaused<span style="color:#eceff4">)}</span><span style="color:#81a1c1">&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">{</span>isPaused <span style="color:#81a1c1">?</span> <span style="color:#a3be8c">&#34;Resume&#34;</span> <span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;Pause&#34;</span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span><span style="color:#bf616a">/button&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span><span style="color:#bf616a">/p&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p><a href="https://codesandbox.io/s/awesome-gareth-qr9gs?file=/src/App.js">You can run the code here</a>.</p> +<p>We removed the <code>speed</code> state and instead added an <code>isPaused</code> state variable, which then controls if the timer is being increased.</p> +<p>But <code>setInterval</code> is not the right way to do animations, as it doesn&rsquo;t synchronize with the browser&rsquo;s re-painting mechanism. This is where <a href="https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame"><code>requestAnimationFrame</code></a> comes in, which basically tells the browser to <em>run the given callback before the next repaint</em>.</p> +<p>Before we switch to it, let us first rewrite the component so that it uses <code>setTimeout</code> instead of <code>setInterval</code>, as that will be nearly identical to the structure of the correct version with <code>requestAnimationFrame</code>.</p> +<p><em>Interestingly enough, this example already contains the same issue as the final version with <code>requestAnimationFrame</code>, but it is much harder to trigger.</em></p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> Counter<span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> <span style="color:#eceff4">[</span>counter<span style="color:#eceff4">,</span> setCounter<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> useState<span style="color:#eceff4">(</span><span style="color:#b48ead">0</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> <span style="color:#eceff4">[</span>isPaused<span style="color:#eceff4">,</span> setIsPaused<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> useState<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">true</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> useEffect<span style="color:#eceff4">(()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">!</span>isPaused<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">let</span> timerId +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> f <span style="color:#81a1c1">=</span> <span style="color:#eceff4">()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> setCounter<span style="color:#eceff4">(</span>x <span style="color:#eceff4">=&gt;</span> x <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Since `f` is only called in a `setTimeout` and not +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// `setInterval`, it needs to re-schedule itself to run +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// again after it finishes. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> timerId <span style="color:#81a1c1">=</span> setTimeout<span style="color:#eceff4">(</span>f<span style="color:#eceff4">,</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// The initial run is also scheduled via `setTimeout` +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// to keep this in line with how `requestAnimationFrame` +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// works, and to make the code overall more consistent +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// in the way it executes. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> timerId <span style="color:#81a1c1">=</span> setTimeout<span style="color:#eceff4">(</span>f<span style="color:#eceff4">,</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">()</span> <span style="color:#eceff4">=&gt;</span> clearTimeout<span style="color:#eceff4">(</span>timerId<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">},</span> <span style="color:#eceff4">[</span>isPaused<span style="color:#eceff4">])</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">(</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span>p<span style="color:#81a1c1">&gt;</span> +</span></span><span style="display:flex;"><span> Counter<span style="color:#81a1c1">:</span> <span style="color:#eceff4">{</span>counter<span style="color:#eceff4">}</span> <span style="color:#eceff4">...{</span><span style="color:#a3be8c">&#34; &#34;</span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span>button onClick<span style="color:#81a1c1">=</span><span style="color:#eceff4">{()</span> <span style="color:#eceff4">=&gt;</span> setIsPaused<span style="color:#eceff4">(</span><span style="color:#81a1c1">!</span>isPaused<span style="color:#eceff4">)}</span><span style="color:#81a1c1">&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">{</span>isPaused <span style="color:#81a1c1">?</span> <span style="color:#a3be8c">&#34;Resume&#34;</span> <span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;Pause&#34;</span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span><span style="color:#bf616a">/button&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span><span style="color:#bf616a">/p&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p><a href="https://codesandbox.io/s/intelligent-liskov-jvgyr?file=/src/App.js">You can try the code here</a>.</p> +<p>A few things changed in this version. We extract our update logic into a separate function <code>f</code> which is the invoked using <code>setTimeout(f, 1)</code> for the first time, and after that it schedules itself to run again as it finishes, using <code>setTimeout(f, 1)</code>. This might seem strange, but it is exactly how <code>requestAnimationFrame</code> works.</p> +<p>Now for the final version with <code>requestAnimationFrame</code>, we simply use <code>requestAnimationFrame(f)</code> in place of <code>setTimeout(f, 1)</code>, and <code>cancelAnimationFrame</code> in place of <code>clearTimeout</code>. This code tells the browser to run <code>f</code> before it will perform its next repaint, which in most cases will be 60 times per second, giving us a nice and smooth animation.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> Counter<span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> <span style="color:#eceff4">[</span>counter<span style="color:#eceff4">,</span> setCounter<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> useState<span style="color:#eceff4">(</span><span style="color:#b48ead">0</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> <span style="color:#eceff4">[</span>isPaused<span style="color:#eceff4">,</span> setIsPaused<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> useState<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">true</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> useEffect<span style="color:#eceff4">(()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">!</span>isPaused<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">let</span> timerId +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> f <span style="color:#81a1c1">=</span> <span style="color:#eceff4">()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> setCounter<span style="color:#eceff4">(</span>x <span style="color:#eceff4">=&gt;</span> x <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> timerId <span style="color:#81a1c1">=</span> requestAnimationFrame<span style="color:#eceff4">(</span>f<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> timerId <span style="color:#81a1c1">=</span> requestAnimationFrame<span style="color:#eceff4">(</span>f<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">()</span> <span style="color:#eceff4">=&gt;</span> cancelAnimationFrame<span style="color:#eceff4">(</span>timerId<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">},</span> <span style="color:#eceff4">[</span>isPaused<span style="color:#eceff4">])</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">(</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span>p<span style="color:#81a1c1">&gt;</span> +</span></span><span style="display:flex;"><span> Counter<span style="color:#81a1c1">:</span> <span style="color:#eceff4">{</span>counter<span style="color:#eceff4">}</span> <span style="color:#eceff4">...{</span><span style="color:#a3be8c">&#34; &#34;</span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span>button onClick<span style="color:#81a1c1">=</span><span style="color:#eceff4">{()</span> <span style="color:#eceff4">=&gt;</span> setIsPaused<span style="color:#eceff4">(</span><span style="color:#81a1c1">!</span>isPaused<span style="color:#eceff4">)}</span><span style="color:#81a1c1">&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">{</span>isPaused <span style="color:#81a1c1">?</span> <span style="color:#a3be8c">&#34;Resume&#34;</span> <span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;Pause&#34;</span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span><span style="color:#bf616a">/button&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span><span style="color:#bf616a">/p&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p><a href="https://codesandbox.io/s/priceless-bogdan-up4zw?file=/src/App.js">You can try the code here</a>.</p> +<p>Now all it takes is to click the <code>Resume</code> / <code>Pause</code> button really fast, and in a couple of tries you should see the counter will ignore the button and keep increasing despite being paused.</p> +<p>This seems very strange, since we&rsquo;re telling React to cleanup the request after the button is pressed. The thing is, despite what people say, <code>useEffect</code> is not actually the same as <code>componentDidUpdate</code>. The documentation actually mentions this at one point, but it didn&rsquo;t occur to me at first what consequences it would have. The problem is the effect passed to <code>useEffect</code> is not run synchronously after the DOM is updated from the render call, but rahter <em>at some point later</em>. This means the browser isn&rsquo;t blocked by the update logic and the app feels more responsive. Specifically in this case, the browser is able to re-paint before the effect (or its cleanup) is run.</p> +<p>In the case of <code>document.title = ...</code> we didn&rsquo;t really care if the title was updated a few milliseconds later, but in the case of <code>requestAnimationFrame</code> it does make a difference. The problem is a new animation frame will be requested before the cleanup function of <code>useEffect</code> is called, since the cleanup is not run synchronously. This is essentially a timing issue, where <em>sometimes</em> the browser will re-paint right between our component rendering to the DOM, and the cleanup function being called. This means our <code>f</code> gets a chance to schedule itself again before it is cleaned up, and essentially escapes our cleanup logic.</p> +<p>Lucky for us, there is an easy fix. Apart from <code>useEffect</code>, there is also a <code>useLayoutEffect</code> hook which has exactly the same arguments and works the same way, <strong>except it runs synchronously after the DOM is updated</strong>. This is exactly what we need, as it will cancel the current animation frame request before a new one has a chance to be queued.</p> +<p>The fixed code is exactly the same, except for <code>useEffect</code> being replaced by <code>useLayoutEffect</code></p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> Counter<span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> <span style="color:#eceff4">[</span>counter<span style="color:#eceff4">,</span> setCounter<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> useState<span style="color:#eceff4">(</span><span style="color:#b48ead">0</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> <span style="color:#eceff4">[</span>isPaused<span style="color:#eceff4">,</span> setIsPaused<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> useState<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">true</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> useLayoutEffect<span style="color:#eceff4">(()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">!</span>isPaused<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">let</span> timerId +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">const</span> f <span style="color:#81a1c1">=</span> <span style="color:#eceff4">()</span> <span style="color:#eceff4">=&gt;</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> setCounter<span style="color:#eceff4">(</span>x <span style="color:#eceff4">=&gt;</span> x <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> timerId <span style="color:#81a1c1">=</span> requestAnimationFrame<span style="color:#eceff4">(</span>f<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> timerId <span style="color:#81a1c1">=</span> requestAnimationFrame<span style="color:#eceff4">(</span>f<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">()</span> <span style="color:#eceff4">=&gt;</span> cancelAnimationFrame<span style="color:#eceff4">(</span>timerId<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">},</span> <span style="color:#eceff4">[</span>isPaused<span style="color:#eceff4">])</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">(</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span>p<span style="color:#81a1c1">&gt;</span> +</span></span><span style="display:flex;"><span> Counter<span style="color:#81a1c1">:</span> <span style="color:#eceff4">{</span>counter<span style="color:#eceff4">}</span> <span style="color:#eceff4">...{</span><span style="color:#a3be8c">&#34; &#34;</span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span>button onClick<span style="color:#81a1c1">=</span><span style="color:#eceff4">{()</span> <span style="color:#eceff4">=&gt;</span> setIsPaused<span style="color:#eceff4">(</span><span style="color:#81a1c1">!</span>isPaused<span style="color:#eceff4">)}</span><span style="color:#81a1c1">&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">{</span>isPaused <span style="color:#81a1c1">?</span> <span style="color:#a3be8c">&#34;Resume&#34;</span> <span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;Pause&#34;</span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span><span style="color:#bf616a">/button&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span><span style="color:#bf616a">/p&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p><a href="https://codesandbox.io/s/falling-field-rs8pb?file=/src/App.js">You can try the code here</a></p> +<h2 id="conclusion-and-references">Conclusion and references</h2> +<p>This article is a good example on why reading documentation and paying attention to detail is important. When learning about hooks I remember hearing something along the lines of <em><code>useEffect</code> fires the effect asynchronously later</em>, it didn&rsquo;t immediately prompt me to ask the question if that could cause any issues, or what are some other use cases for <code>useLayoutEffect</code>. The example I&rsquo;ve seen people mention with it over and over again is <em>resizing windows</em> or <em>DOM mutations</em>, where <code>useEffect</code> would cause a flicker in the UI and <code>useLayoutEffect</code> wouldn&rsquo;t. Interestingly, this is the same problem as we&rsquo;re facing with <code>requestAnimationFrame</code>, as in both cases we want to do something before the browser has a chance to repaint. Only in the case of <code>requestAnimationFrame</code> the repaint does more than a UI flicker, it breaks our code.</p> +<h3 id="references">References</h3> +<ul> +<li><a href="https://reactjs.org/docs/hooks-effect.html">Using the Effect Hook</a></li> +<li><a href="https://reactjs.org/docs/hooks-reference.html#uselayouteffect">React Hooks - <code>useLayoutEffect</code></a></li> +<li><a href="https://github.com/streamich/react-use">react-use</a></li> +<li><a href="https://github.com/streamich/react-use/issues/76">react-use - issue #76 <em>cancelAnimationFrame may not work well in useRaf hook</em></a></li> +<li><a href="https://github.com/streamich/react-use/pull/77">react-use - fix of the <code>useRaf</code> hook</a></li> +<li><a href="https://github.com/streamich/react-use/commit/5d7434867c2f62e2383ed407ac1a0ad25e6d3f86#diff-aab454c8a7c03a31d945af5f20756009">react-use commit fixing the above issue</a></li> +<li><a href="https://stackoverflow.com/questions/53781632/whats-useeffect-execution-order-and-its-internal-clean-up-logic-in-react-hooks">StackOverflow question on useEffect vs useLayoutEffect</a></li> +</ul> + + + + + SSH Tunnel - Local, Remote and Dynamic Port Forwarding + https://blog.jakuba.net/ssh-tunnel---local-remote-and-dynamic-port-forwarding/ + Mon, 04 May 2020 10:00:00 +0200 + + https://blog.jakuba.net/ssh-tunnel---local-remote-and-dynamic-port-forwarding/ + <p>SSH tunneling is an extremely useful feature of SSH that is very often googled, but less often understood enough to use without a reference. In this post I hope to explain it in such a way that you&rsquo;ll have no confusion about when to use SHH&rsquo;s local, remote, or even dynamic port forwarding. In its essence, port forwarding allows SSH to securely create an encrypted communication channel (a tunnel) between two computers on the network. We can use this channel to run commands on the remote server, expose a local port in a remote computer, expose a remote port on the local computer, or route traffic via a SOCKS proxy (more on this later).</p> +<h2 id="background">Background</h2> +<p>But first a tiny bit of background on how SSH works and why it&rsquo;s secure. If you just want to get to the practical bits, feel free to skip this section and jump straight to <em>Local Port Forwarding</em>. You don&rsquo;t need to understand it to use SSH tunnels in practice.</p> +<p>There are three types of encryption used at different stages: Diffie-Hellman, RSA, and AES (or other algorithms depending on configuration). If you&rsquo;ve ever configured nginx and run into something called <code>dhparam</code> or <code>ssl_dhparam</code>, the <code>dh</code> in there stands for the <a href="https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange">Diffie-Hellman algorithm</a>, which is an amazingly simple algorithm to exchange a secret key over an insecure communication channel, without any prior knowledge. If you understand exponentiation (e.g. $2^{10} = 1024$) and modulo (e.g. $16 \mod 5 = 1$) you can understand Diffie-Hellman, as it&rsquo;s only a few steps that could be done even on paper.</p> +<p>The issue with Diffiel-Hellman is that while you can exchange a secret, you don&rsquo;t really know who you&rsquo;re exchanging it with, and is vulnerable to the main-in-the-middle attack (someone could pretend to be the server and exchange the key with you instead). That&rsquo;s where one more step comes in and the server uses its private key to sign a hash of some of the Diffie-Hellman parameters (<a href="https://tools.ietf.org/html/rfc4253#section-8">check out section 8 of the RFC on what exactly gets signed</a>), and the client then verifies the hosts signature using its public key. This is where SSH asks you to verify the host fingerprint, which is the fingerprint of its public key, and if you say yes, it means you&rsquo;re validating the server truly is who they say they are (and not an attacker), and they key exchange can continue. If you always say <code>yes</code> without verifying the host key, you&rsquo;re vulnerable to a man-in-the-middle-attack.</p> +<p>After the server authenticity is confirmed, and the client and the server use Diffie-Hellman to negotiate a session key, which is then used to encrypt all of the traffic between them. You might be thinking why not use the already existing RSA keys (public/private keypair) of the client/server to encrypt the traffic? The answer is simple: asymmetric encryption is slow. Instead, SSH uses symmetric encryption (e.g. AES) to encrypt the traffic.</p> +<p>Lastly, the client is authorized against the server using it&rsquo;s RSA keypair. The server will simply encrypt a random value using the client&rsquo;s public key (taken from <code>~/.ssh/authorized_keys</code>) and send it over, the client verifies itself by being able to decrypt the message (because it owns the private key) and sends it back. If the values match, the client&rsquo;s identity is verified and is authenticated now. (<em>Note that there are a few technical details, such as hashing the values together with the session key, but those are not important for understanding the overall flow</em>.)</p> +<h2 id="local-port-forwarding">Local Port Forwarding</h2> +<p>The first forwarding mode we&rsquo;ll look at is <strong>local port forwarding</strong> with the <code>-L</code> flag. It&rsquo;s called <em>local</em> because it allows us to forward connections from a local port to a different port on another computer on the network, using a secure SSH connection.</p> +<p>Say that you have a database (e.g. PostgreSQL) running on a server <code>example.com</code> on port <code>5432</code>. The server is configured in such a way that only the SSH port <code>22</code> is open, and thus you can&rsquo;t connect directly via <code>psql -h example.com -p 5432</code>. You could SSH to the server and run <code>psql -h localhost -p 5432</code> on there, but what if you wanted to use a GUI client for the database, and connect to the server directly?</p> +<p>With SSH you can simply forward an arbitrary local port, say <code>4000</code>, to the port <code>5432</code> on the server, but in such a way that the connection to <code>5432</code> would come as if from inside the server, and thus would be allowed. To do this we run:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>ssh -N -L 4000:localhost:5432 user@example.com +</span></span></code></pre></div><p><em>We&rsquo;ll use the <code>-N</code> flag with all commands, which tell SSH to not start a shell (or execute a given command) and only forward ports. Personally I find this useful to distinguish which SSH session I use for forwarding and which ones might be just regular shell connections. You can of course forward while starting a remote shell (just omit the <code>-N</code> flag).</em></p> +<p>The above command will connect to <code>user@example.com</code> and start forwarding the local port <code>4000</code> to <code>localhost:5432</code> on the server. This means we can now run <code>psql -h localhost -p 4000</code>, and as <code>psql</code> establishes a connection to <code>localhost</code> on port <code>4000</code>, SSH will securely forward the connection to <code>example.com</code>, where it connects to <code>localhost:5432</code>. This way <code>psql</code> doesn&rsquo;t even know it&rsquo;s connecting to a database running on a far away server.</p> +<p>One interesting tip is that we could forward to something else than <code>localhost</code> on <code>example.com</code>. Say that we have a second host named <code>foobar.org</code>, which is accessible only from the <code>example.com</code> server, but not accessible from your machine.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>ssh -N -L 4000:foobar.org:5432 user@example.com +</span></span></code></pre></div><p>This way a connection to <code>localhost:4000</code> on your machine would get forwarded through <code>example.com</code> to connect to <code>foobar.org</code> on port <code>5432</code>. In theory, you could also use this to bypass a firewall blocking direct connections from your computer, but dynamic port forwarding solves this problem more naturally by creating a SOCKS proxy (as we&rsquo;ll see shortly).</p> +<h2 id="remote-port-forwarding">Remote Port Forwarding</h2> +<p>While local forwarding allows us to forward local connections to a remote port, with remote port forwarding we can accept connections on a remote server, and forward those to a local port on our machine. Say that we have a folder we want to share with a friend via our <code>example.com</code> server, but we don&rsquo;t want to copy the files over. We could start up a web server using python</p> +<pre tabindex="0"><code>$ python -m http.server +</code></pre><p>which creates a simple HTTP server on port <code>8000</code> that servers files from the current directory. We could then use SSH to remotly forward port <code>4000</code> on the server <code>example.com</code> to <code>localhost:8000</code> as follows:</p> +<pre tabindex="0"><code>ssh -N -R 4000:localhost:8000 user@example.com +</code></pre><p>Now you can tell your friend to go to <code>http://example.com:4000</code>, and SSH will accept his connection, and forward it to your computer to <code>localhost:8000</code>. There is one small catch, and that forwarding ports like this requires you to edit the configuration of SSH on the server. Specifically, you need add (or edit) <code>GatewayPorts yes</code> to <code>/etc/ssh/sshd_config</code> and restart the SSH daemon (via <code>sudo systemctl restart sshd</code>), otherwise SSH won&rsquo;t allow you to use this form of port forwarding.</p> +<p>Services like <a href="https://ngrok.com/">ngrok.com</a> basically give you a fancy UI to remote port forwarding. They give you a CLI which you can run to make a local port available <em>on the internet</em> via a publically accesible subdomain. If you have your own server (which you can get for free on AWS/GCP, or for a few dollars per month on many providers), you can do exactly the same thing with a single command with SSH using remote port forwarding without any limitations, and save yourself some money :)</p> +<h2 id="dynamic-port-forwarding">Dynamic Port Forwarding</h2> +<p>The last type of forwarding is called <em>dynamic port forwarding</em>, which is perhaps a slightly confusing name, because the way you use it is different from the two previous forwarding mechanisms. With dynamic port forwarding you only specify the local port to bind to using the <code>-D</code> parameter, and SSH will then determine where to forward connections based on the SOCKS protocol. The way this works is that SSH creates a SOCKS server which acts as a proxy which you can use in other applications.</p> +<p>Let&rsquo;s say you still have the <code>example.com</code> server with the SSH port open. It is also part of a private network with other servers on it, say a website <code>private.example.com</code>, which is not accesible directly from the internet, but is accesible from <code>example.com</code>. First we connect to <code>example.com</code> with dynamic port forwarding:</p> +<pre tabindex="0"><code>ssh -N -D 5000 user@example.com +</code></pre><p>To connect to <code>private.example.com</code> we need to configure the web browser to use our SOCKS proxy. In Firefox this can be done with <code>Network Settings -&gt; Manual proxy configuration -&gt; SOCKS host</code> and select <code>SOCKS v5</code> and set <code>SOCKS Host</code> to <code>localhost</code> and <code>Port</code> to <code>5000</code>. You can also check <code>Proxy DNS when using SOCKS v5</code> to resolve DNS using your SOCKS proxy, instead of resolving the hostname on your machine prior to making the request.</p> +<p>After this, you can just press <code>OK</code> and type <code>private.example.com</code> in the address bar and hit enter, and SSH will do the rest. Specifically it will connect to <code>localhost:5000</code> via the SOCKS protocol and forward your request via the server to the website <code>private.example.com</code>. In practice, this is as if you used a VPN to connect to the private network. The downside is you need to configure your browser (and any other program) which you want to connect via the proxy. It doesn&rsquo;t connect your whole computer inside the network as a VPN program could, but this could also be considered a benefit if you just want to access something in isolation.</p> +<p>If you&rsquo;re using Chrome (or Chromium), you can use this nifty one-liner to start a new instance with the SOCKS configuration pre-filled:</p> +<pre tabindex="0"><code>$ chromium --proxy-server=socks://localhost:5000 \ + --user-data-dir=/tmp/foo +</code></pre><p>The <code>--proxy-server=socks://localhost:5000</code> option does exactly what it says, it sets the SOCKS proxy configuration option. The <code>--user-data-dir</code> option is a nice addition, because this way you could have a completely separate user profile for the proxied browser.</p> +<p>As a final note, you can use dynamic port forwarding to do things like access a website avaialble only in a specific country if you have a server <code>example.com</code> which is hosted in that country. Or you could connect to websites on your company&rsquo;s private network as long as you can SSH to any server on the network.</p> +<h2 id="conclusion">Conclusion</h2> +<p>We covered three ways of port forwarding:</p> +<ul> +<li>Local port forwarding used for tunneling local connections to a port on a remote server.</li> +<li>Remote port forwarding used for tunneling remote connections to a port on a local server.</li> +<li>Dynamic port forwarding used for creating a TCP proxy via a remote host.</li> +</ul> +<p>The given examples only scratch the surface of possible use cases. There are many cases where local or remote port forwarding can be useful during debugging multi-server architectures. You could even create multi-hop SSH tunnels where you tunnel from <code>A</code> to <code>B</code>, and then from <code>B</code> to <code>C</code>, e.g.</p> +<pre tabindex="0"><code>ssh -L 9999:host2:1234 -N host1 +</code></pre><p>You can even use the first <code>ssh</code> command to run <code>ssh</code> on the remote host and create a second tunnel as the first one is created</p> +<pre tabindex="0"><code>ssh -L 9999:localhost:9999 host1 ssh -L 9999:localhost:1234 -N host2 +</code></pre><p>which is not only cool, but also creates a secure SSH tunnel from <code>host1</code> to <code>host2</code> as opposed to the first method which does not (<a href="https://superuser.com/questions/96489/an-ssh-tunnel-via-multiple-hops">see this answer on SuperUser for more interesting examples</a>.</p> +<p>Most importantly, play around and experiment with SSH when you get a chance! While not every combination of tunnels might be the best solution to your problem, there were certainly many times where knowing how to solve a problem using SSH tunnels saved me hours of otherwise tedious work (usually involving moving stuff around between servers).</p> + + + + + Git Command Overview with Useful Flags and Aliases + https://blog.jakuba.net/git-command-overview-with-useful-flags-and-aliases/ + Sun, 03 May 2020 23:28:14 +0200 + + https://blog.jakuba.net/git-command-overview-with-useful-flags-and-aliases/ + <p>This post is a short guide to making your git usage a little more efficient. We&rsquo;re not going to cover how git works in depth. Instead, we&rsquo;ll look at the most common operations and useful flags, with the goal to create a set of bash or zsh aliases for daily use. A completel list of aliases presented in the article is summarized at the end of the article.</p> +<p>Each section will first briefly describe the command, some of its useful flags, and then suggest a set of mnemonic aliases with their usage. Contrary to what some people might thinks, we won&rsquo;t use the builtin git alias functionality using <code>git config</code> (that is e.g. <code>git config --global alias.co checkout</code>), but rather plain shell aliases such as <code>alias gco=&quot;git checkout&quot;</code>. The reason is simple, it is much easier and faster to type <code>gco</code> than <code>git co</code>, which makes git usage more enjoyable. Since (almost) all of our aliases will be prefixed with <code>g</code> (such as <code>ga</code>, <code>gco</code>, <code>gc</code>, &hellip;) they will be just as easy to <em>discover</em> if you ever forget them as their <code>git config</code> alias counterpart.</p> +<h2 id="git-status"><code>git status</code></h2> +<p>We&rsquo;re going to skip ahead alphabetically and cover <code>git status</code> right now, as it will be useful in explaining the other commands. Everyone who ever tried git had to write <code>git status</code> at some point, yet of all the people I&rsquo;ve met, only a few know of its extremely useful variant <code>git status -sb</code>. Let me illustrate on a straightforward example where we simply create three file <code>f1, f2, f3</code>, modify some of them, and look at how the output of <code>git status</code> differs from <code>git status -sb</code> (I tried to make the example self-contained so you can try it yourself):</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ mkdir status-demo +</span></span><span style="display:flex;"><span>$ <span style="color:#81a1c1">cd</span> status-demo +</span></span><span style="display:flex;"><span>$ git init +</span></span><span style="display:flex;"><span>Initialized empty Git repository in /home/darth/projects/status-demo/.git/ +</span></span><span style="display:flex;"><span>$ <span style="color:#616e87;font-style:italic"># This lets us make an empty commit</span> +</span></span><span style="display:flex;"><span>$ git commit -m <span style="color:#a3be8c">&#34;Initial commit&#34;</span> --allow-empty +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">[</span>master <span style="color:#81a1c1">(</span>root-commit<span style="color:#81a1c1">)</span> 35773eb<span style="color:#81a1c1">]</span> Initial commit +</span></span><span style="display:flex;"><span>$ touch f1 f2 f3 +</span></span><span style="display:flex;"><span>$ git status +</span></span><span style="display:flex;"><span>On branch master +</span></span><span style="display:flex;"><span>Untracked files: +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">(</span>use <span style="color:#a3be8c">&#34;git add &lt;file&gt;...&#34;</span> to include in what will be committed<span style="color:#81a1c1">)</span> +</span></span><span style="display:flex;"><span> f1 +</span></span><span style="display:flex;"><span> f2 +</span></span><span style="display:flex;"><span> f3 +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>nothing added to commit but untracked files present <span style="color:#81a1c1">(</span>use <span style="color:#a3be8c">&#34;git add&#34;</span> to track<span style="color:#81a1c1">)</span> +</span></span><span style="display:flex;"><span>$ git status -sb +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">## master</span> +</span></span><span style="display:flex;"><span>?? f1 +</span></span><span style="display:flex;"><span>?? f2 +</span></span><span style="display:flex;"><span>?? f3 +</span></span><span style="display:flex;"><span>$ git add . +</span></span><span style="display:flex;"><span>$ git commit -m <span style="color:#a3be8c">&#34;Add a few files&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">[</span>master b97a26a<span style="color:#81a1c1">]</span> Add a few files +</span></span><span style="display:flex;"><span> <span style="color:#b48ead">3</span> files changed, <span style="color:#b48ead">0</span> insertions<span style="color:#81a1c1">(</span>+<span style="color:#81a1c1">)</span>, <span style="color:#b48ead">0</span> deletions<span style="color:#81a1c1">(</span>-<span style="color:#81a1c1">)</span> +</span></span><span style="display:flex;"><span> create mode <span style="color:#b48ead">100644</span> f1 +</span></span><span style="display:flex;"><span> create mode <span style="color:#b48ead">100644</span> f2 +</span></span><span style="display:flex;"><span> create mode <span style="color:#b48ead">100644</span> f3 +</span></span><span style="display:flex;"><span>$ <span style="color:#81a1c1">echo</span> x &gt; f1 +</span></span><span style="display:flex;"><span>$ rm f2 +</span></span><span style="display:flex;"><span>$ <span style="color:#81a1c1">echo</span> x &gt; f3 +</span></span><span style="display:flex;"><span>$ <span style="color:#81a1c1">echo</span> x &gt; f4 <span style="color:#616e87;font-style:italic"># new file</span> +</span></span><span style="display:flex;"><span>$ git add f1 +</span></span><span style="display:flex;"><span>$ git status +</span></span><span style="display:flex;"><span>On branch master +</span></span><span style="display:flex;"><span>Changes to be committed: +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">(</span>use <span style="color:#a3be8c">&#34;git restore --staged &lt;file&gt;...&#34;</span> to unstage<span style="color:#81a1c1">)</span> +</span></span><span style="display:flex;"><span> modified: f1 +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>Changes not staged <span style="color:#81a1c1;font-weight:bold">for</span> commit: +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">(</span>use <span style="color:#a3be8c">&#34;git add/rm &lt;file&gt;...&#34;</span> to update what will be committed<span style="color:#81a1c1">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">(</span>use <span style="color:#a3be8c">&#34;git restore &lt;file&gt;...&#34;</span> to discard changes in working directory<span style="color:#81a1c1">)</span> +</span></span><span style="display:flex;"><span> deleted: f2 +</span></span><span style="display:flex;"><span> modified: f3 +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>Untracked files: +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">(</span>use <span style="color:#a3be8c">&#34;git add &lt;file&gt;...&#34;</span> to include in what will be committed<span style="color:#81a1c1">)</span> +</span></span><span style="display:flex;"><span> f4 +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>$ git status -sb +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">## master</span> +</span></span><span style="display:flex;"><span>M f1 +</span></span><span style="display:flex;"><span> D f2 +</span></span><span style="display:flex;"><span> M f3 +</span></span><span style="display:flex;"><span>?? f4 +</span></span></code></pre></div><p><em>The code examples are intentionally a bit verbose to keep them reproducible. You can simply follow along command by command in your own terminal. Playing around with <code>git</code> is a great way to learn!</em></p> +<p>Since the code highlighter on this post does not capture the terminal output highlighting, here&rsquo;s the last two commands in a screenshot, showing how <code>git status</code> and <code>git status -sb</code> share the same color highlighting, but only format the output differently.</p> +<p><img src="https://i.imgur.com/2HmXwzT.png" alt="git status vs git status -sb"></p> +<p><code>git status -sb</code> simply drops all of the text and additional information, and keeps the important parts of the output - what branch are we on and what has changed in what way. It will mark modifications with <code>M</code>, deletions with <code>D</code>, and newly added files with <code>??</code>. The column in which the <code>M/D</code> is displayed also signifies if the change was staged. For example, the modifications to <code>f1</code> were staged with <code>git add</code>, hence the <code>M</code> displays in the left column and in yellow (same as regular <code>git status</code>). Modifications to <code>f3</code> and the deletion of <code>f2</code> were not staged, which is why they&rsquo;re in green in the second column.</p> +<p>While this might be a little confusing at first, I promise that it only takes a couple of minutes to get used to this, and that your git experience will be much improved from using <code>git status -sb</code> over the regular <code>git status</code>. Suddenly your terminal won&rsquo;t fill half the screen with each status, and you won&rsquo;t have to scroll around to find your previous commands after using <code>git status</code> for a few times. It might seem like a small thing, but at least personally for me, this single command (along with the suggested alias) transformed my git usage from <em>annoying</em> to <em>joyful</em>.</p> +<p>To make the matters even more controversial, I suggest a different alias for <code>git status -sb</code>, and that is:</p> +<ul> +<li><code>alias s=&quot;git status -sb&quot;</code></li> +</ul> +<p>Now you might think this is insane, a single letter alias for an arbitrary git command? The reason is, at least in my personal experience, that this is the most common command I use out of all terminal commands. Here are the top 6 commands from my history:</p> +<pre tabindex="0"><code>1 648 6.48065% s +2 640 6.40064% cd +3 505 5.05051% gc +4 410 4.10041% vim +5 331 3.31033% docker +6 292 2.92029% ga +7 266 2.66027% ls +</code></pre><p>You can create a similar statisic for yourself using the following command (<a href="https://dev.to/abhinav/which-is-the-most-used-command-in-your-shell-history-5ca1">reference</a>):</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#81a1c1">history</span> <span style="color:#eceff4">|</span> awk <span style="color:#a3be8c">&#39;{CMD[$2]++;count++;}END { for (a in CMD)print CMD[a] &#34; &#34; CMD[a]/count*100 &#34;% &#34; a;}&#39;</span> <span style="color:#eceff4">|</span> grep -v <span style="color:#a3be8c">&#34;./&#34;</span> <span style="color:#eceff4">|</span> column -c3 -s <span style="color:#a3be8c">&#34; &#34;</span> -t <span style="color:#eceff4">|</span> sort -nr <span style="color:#eceff4">|</span> nl <span style="color:#eceff4">|</span> head -n10 +</span></span></code></pre></div><p>At least in my case <code>s</code> is a winner and beats even <code>cd</code>, followed by <code>gc</code> (the <code>git commit -v</code> from before). This makes sense, because every time you would want to make a new git commit, you&rsquo;d <code>cd</code> into the directory and check the status.</p> +<p>This statistic (at least for my git usage) confirms that <code>git status -sb</code> is not just a random command, it is <strong>the command</strong>, and as such it deserves a special alias. Some people suggest using <code>alias gs=&quot;git status -sb&quot;</code>, which might be leaning on the safe side, and I definitely started out that way. But is there really anything else that would deserve the glorious one letter <code>s</code> alias than <code>git status -sb</code>?</p> +<h2 id="git-add"><code>git add</code></h2> +<p>Git separates the working tree (the files being edited) from the index, that is the staged changes which are ready to be comitted. Before using <code>git commit</code>, we have to stage our changes using <code>git add</code>. But since this doesn&rsquo;t have to include all of the changes, <code>git add</code> comes with quite a few options (check <code>man git-add</code>).</p> +<p>For example, <code>git add -u</code> only stages files that were modified (or deleted), but not newly added files. To add all modifications, deletions and additions, one can simply run <code>git add .</code> But sometimes we want to be more granular than adding whole files. This is where <code>git add -p</code> (or <code>--patch</code>) comes in, which launches an interactive mode, prompting the user with each change whether they want to add it to the index.</p> +<p>Aliases:</p> +<ul> +<li><code>alias ga=&quot;git add&quot;</code></li> +<li><code>alias gau=&quot;git add -u&quot;</code></li> +<li><code>alias gap=&quot;git add -p&quot;</code></li> +</ul> +<h2 id="git-branch"><code>git branch</code></h2> +<p>Branching is an integral art of git, and as such the <code>git branch</code> command deserves at least one alias of its own. Lucky for us we can rely on <code>git checkout</code> for most of the branching shenanigans, and as such we only mention <code>git branch --all</code>. Deleting branches is sometimes useful as well, but as there are multiple ways - with some people preferring <code>-d</code> and some <code>-D</code> - we leave this out of the aliases.</p> +<ul> +<li><code>alias gb=&quot;git branch&quot;</code></li> +<li><code>alias gba=&quot;git branch --all&quot;</code></li> +</ul> +<h2 id="git-commit"><code>git commit</code></h2> +<p>Creating new commits is one of the most common operations when using git, and as such we want to have a decent setup for it. Firstly, <code>git commit</code> has a <code>-v</code> flag which causes it to show a complete diff when it opens the editor for the commit message.</p> +<p>One benefit of using <code>git commit -v</code> as opposed to <code>git commit -m &quot;Some message&quot;</code> is that you get one last chance to inspect what is being changed. This might be as simple as holding down <code>Ctrl-D</code> to scroll down in Vim in a matter of seconds, but there are certainly times where such quick visual inspection can catch unexpected files being committed (especially when the size of the diff is much larger/smaller than expected, or weird characters pop up). As such, we&rsquo;ll use <code>-v</code> as a default option for all our <code>git commit</code> commands.</p> +<p>We can also use <code>-a</code> to automatically stage all modified files before committing (similar to <code>git add -u</code>).</p> +<p>Lastly, there is the <code>--amend</code> options, which gives us a way to <em>fix</em> the last commit if it hasn&rsquo;t been pushed. <strong>Since git history is immutable, this does not actually change the commit, but instead creates a new one and resets <code>HEAD</code> to it.</strong> This is critical information, because it means you should not <code>--amend</code> after you used <code>git push</code>. That is after some other computer contains the old commit. If you do <code>git commit --amend</code> after pushing, you will be required to force push (<code>git push --force</code>), as your tree is not a simple extension of the tree on the origin server, and needs to be overwritten by your local copy. This is similar to using <code>git rebase</code> or <code>git reset --hard</code> as we&rsquo;ll see later. In simple terms, if you <code>git push --force</code> you&rsquo;re in some sense <em>overwriting</em> <code>origin</code>, and if someone else ran <code>git fetch</code> (or <code>git pull</code>) in the meantime, they will have a different local tree that won&rsquo;t be compatible with <code>origin</code> after you for push anymore. There are definitely ways to work around these problems, but none of them are trivial, and out of the scope of this article.</p> +<p><em>If you&rsquo;re interested in a followup article covering <code>git push --force</code> or some other topic, feel free to leave a comment below the article or message me on twitter</em>.</p> +<ul> +<li><code>alias gc=&quot;git commit -v&quot;</code></li> +<li><code>alias gca=&quot;git commit -v -a&quot;</code></li> +<li><code>alias gcam=&quot;gca --amend&quot;</code> - Here you might want to opt out of the <code>-a</code> depending on your preference.</li> +</ul> +<h2 id="git-cherry-pick"><code>git cherry-pick</code></h2> +<p>Cherry picking allows us to copy (apply) arbitrary commits to our <code>HEAD</code>. While not a common operation it does come in handy from time to time, especially when fixing previous git-related issues. As cherry-picking is very problem specific, we don&rsquo;t introduce any default flags and only use the most basic alias</p> +<ul> +<li><code>alias gch=&quot;git cherry-pick&quot;</code></li> +</ul> +<h2 id="git-checkout"><code>git checkout</code></h2> +<p>Git checkout is our first command that directly manipulates the working tree. First we introduce <code>git checkout &lt;BRANCH&gt;</code> as a way to switch between branches. We can also use this to switch our working tree to an arbitrary commit in the history (as in <code>git checkout &lt;REF&gt;</code>). Surprisingly to some, <code>git checkout</code> is better at creating new branches than <code>git branch</code> is, as it allows us to create the branch and switch to it with a single command <code>git branch -b &lt;BRANCH&gt;</code>.</p> +<p>Lastly, we can use <code>git checkout &lt;FILE&gt;</code> to discard its changes and revert it back to the version in the index, or in case nothing is staged, to <code>HEAD</code>. A small example to illustrate this where we create and commit a new file, then make some changes to it, stage them, make some more changes, use <code>git checkout</code> to reset the unstaged changes, then use <code>git reset</code> to clear the stage, and again <code>git checkout</code> to reset the remaining changes.</p> +<p>One sidenote, consider if we had a file named <code>master</code> while also having a branch named <code>master</code>. If we wanted to use <code>git checkout</code> on the file and wrote <code>git checkout master</code>, git would actually refer to the branch instead. For this reason <code>git</code> provides a <code>--</code> argument, which tells git to process the comes after it as filenames. This means <code>git checkout -- master</code> will apply <code>git checkout</code> on a <strong>file</strong> named <code>master</code>. It&rsquo;s a good idea to use this option every time you want to apply <code>git checkout</code> to a file, as you might forget you have a branch with the same name and get confused about the results (especially if you create lots of temporary branches/files named <code>a</code> or <code>foo</code> or <code>test</code>). For this reason we&rsquo;ll use <code>git checkout -- file.txt</code> as opposed to <code>git checkout file.txt</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ mkdir checkout-demo +</span></span><span style="display:flex;"><span>$ <span style="color:#81a1c1">cd</span> checkout-demo +</span></span><span style="display:flex;"><span>$ <span style="color:#81a1c1">echo</span> aaa &gt; file.txt +</span></span><span style="display:flex;"><span>$ git init +</span></span><span style="display:flex;"><span>Initialized empty Git repository in ~/checkout-demo/.git/ +</span></span><span style="display:flex;"><span>$ git add . +</span></span><span style="display:flex;"><span>$ git commit -m <span style="color:#a3be8c">&#34;Initial commit&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">[</span>master <span style="color:#81a1c1">(</span>root-commit<span style="color:#81a1c1">)</span> 52ae6f1<span style="color:#81a1c1">]</span> Initial commit +</span></span><span style="display:flex;"><span> <span style="color:#b48ead">1</span> file changed, <span style="color:#b48ead">1</span> insertion<span style="color:#81a1c1">(</span>+<span style="color:#81a1c1">)</span> +</span></span><span style="display:flex;"><span> create mode <span style="color:#b48ead">100644</span> file.txt +</span></span><span style="display:flex;"><span>$ <span style="color:#81a1c1">echo</span> bbb &gt;&gt; file.txt +</span></span><span style="display:flex;"><span>$ git status -sb <span style="color:#616e87;font-style:italic">#</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">## master #</span> +</span></span><span style="display:flex;"><span> M file.txt <span style="color:#616e87;font-style:italic"># -------- here the ` M` is</span> +</span></span><span style="display:flex;"><span>$ git add file.txt <span style="color:#616e87;font-style:italic"># in the right column meaning</span> +</span></span><span style="display:flex;"><span>$ <span style="color:#81a1c1">echo</span> ccc &gt;&gt; file.txt <span style="color:#616e87;font-style:italic"># unstaged changes only</span> +</span></span><span style="display:flex;"><span>$ git status -sb <span style="color:#616e87;font-style:italic">#</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">## master #</span> +</span></span><span style="display:flex;"><span>MM file.txt <span style="color:#616e87;font-style:italic"># -------- here we have `MM` for</span> +</span></span><span style="display:flex;"><span>$ cat file.txt <span style="color:#616e87;font-style:italic"># both staged and unstaged</span> +</span></span><span style="display:flex;"><span>aaa <span style="color:#616e87;font-style:italic"># changes</span> +</span></span><span style="display:flex;"><span>bbb <span style="color:#616e87;font-style:italic">#</span> +</span></span><span style="display:flex;"><span>ccc <span style="color:#616e87;font-style:italic">#</span> +</span></span><span style="display:flex;"><span>$ git checkout -- file.txt <span style="color:#616e87;font-style:italic">#</span> +</span></span><span style="display:flex;"><span>$ git status -sb <span style="color:#616e87;font-style:italic">#</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">## master #</span> +</span></span><span style="display:flex;"><span>M file.txt <span style="color:#616e87;font-style:italic"># ------- and finally here the `M `</span> +</span></span><span style="display:flex;"><span>$ cat file.txt <span style="color:#616e87;font-style:italic"># is on the left, signifying</span> +</span></span><span style="display:flex;"><span>aaa <span style="color:#616e87;font-style:italic"># staged changes only</span> +</span></span><span style="display:flex;"><span>bbb <span style="color:#616e87;font-style:italic">#</span> +</span></span><span style="display:flex;"><span>$ git reset <span style="color:#616e87;font-style:italic">#</span> +</span></span><span style="display:flex;"><span>Unstaged changes after reset: <span style="color:#616e87;font-style:italic">#</span> +</span></span><span style="display:flex;"><span>M file.txt <span style="color:#616e87;font-style:italic"># ------- this is not what we *have after*,</span> +</span></span><span style="display:flex;"><span>$ git status -sb <span style="color:#616e87;font-style:italic"># but what *was changed*</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">## master #</span> +</span></span><span style="display:flex;"><span> M file.txt <span style="color:#616e87;font-style:italic"># ------ confirming the output,</span> +</span></span><span style="display:flex;"><span>$ git checkout -- file.txt <span style="color:#616e87;font-style:italic"># `git reset` unstaged our changes</span> +</span></span><span style="display:flex;"><span>$ git status -sb <span style="color:#616e87;font-style:italic"># and now we&#39;re back to ` M`</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">## master</span> +</span></span><span style="display:flex;"><span>$ cat file.txt +</span></span><span style="display:flex;"><span>aaa +</span></span></code></pre></div><p><em>The code examples are intentionally a bit verbose to keep them reproducible. You can simply follow along command by command in your own terminal. Playing around with <code>git</code> is a great way to learn!</em></p> +<p>If you found this example confusing due to the <code>git status -sb</code> outputs not being correctly highlighted, or are confused in general, here&rsquo;s the same thing but in a properly colorized screenshot</p> +<p><img src="https://i.imgur.com/kRj4zKs.png" alt="colorized git checkout with git status -sb"></p> +<p>As noted before, yellow means <em>staged</em>, green means <em>unstaged</em>, and <code>git checkout</code> modifies the unstaged changes, meaning it <em>removes the green ones</em>.</p> +<ul> +<li><code>alias gco=&quot;git checkout&quot;</code></li> +</ul> +<h2 id="git-diff"><code>git diff</code></h2> +<p>Similarly to <code>git status</code>, checking the changes made to the working dir is a very common operation. The <code>git diff</code> has a useful flag which I would recommend using by default, and that is <code>git diff -M</code>. This will allow <code>git diff</code> to detect when a file was renamed. If you rename a file and don&rsquo;t use <code>-M</code>, <code>git diff</code> will show one file as deleted and another one as newly added, as opposed to showing it as a rename.</p> +<p>Note that this option does not work 100% of the time, because git can&rsquo;t know with certainty that a file was renamed. The filesystem doesn&rsquo;t keep any kind of log of rename operations, nor is it written in any kind of metadata. Git will simply look at the contents of the two files, compare them, and if the amount of changes is small enough, it will consider the file as renamed. You can actually specify the threshold for changes with the <code>-M</code> flag, specifically <code>-M90%</code> would tell git to only consider something to be renamed if more than 90% of the file hasn&rsquo;t been changed. By default this is set to 50%. This might seem silly at first, but consider renaming a file in your editor and then making changes to it. You wouldn&rsquo;t necessarily commit things right after the file was renamed, yet you would still expect git to track the rename.</p> +<ul> +<li><code>alias gd=&quot;git diff -M&quot;</code></li> +</ul> +<p>Personally I use <code>git diff</code> so often I devoted a second one-letter alias to it, specifically just <code>d</code> as opposed to <code>gd</code>. That is the following:</p> +<ul> +<li><code>alias d=&quot;git diff -M&quot;</code></li> +</ul> +<p>As opposed to <code>alias s=&quot;git status -sb&quot;</code> I&rsquo;d say this one is more debatable, considering <code>git diff</code> is used much less often than <code>git status</code>.</p> +<p>There is one more useful flag with <code>git diff</code>, and that is <code>--cached</code>. The regular <code>git diff</code> only shows diff between the working directory and the index. That is changes you could possibly stage with <code>git add</code>. But sometimes you might have already staged some changes while leaving others unstaged (say with <code>git add -p</code>) and would like to see only the changes that would be comitted. This is where <code>git diff --cached</code> comes in, which will show the difference between your staged changes and <code>HEAD</code>.</p> +<ul> +<li><code>alias gdc=&quot;git diff -M --cached&quot;</code></li> +</ul> +<p>An honorary mention goes to the <code>--word-diff</code> flag, which is not common enough to make an alias, but still useful to know about and I suggest playing around with it (and also look it up in <code>man git-diff</code>). By default <code>git diff</code> will show how the whole line has changed, but with <code>--word-diff</code> it will try to show diff within the line itself (on single words). This can be useful when making small tweaks to long lines, such as READMEs or documentation, but less so on code (which is why it&rsquo;s not the default).</p> +<h1 id="git-fetch"><code>git fetch</code></h1> +<p>Sometimes people are surprised when they see me using <code>git fetch</code> followed by a <code>git merge --ff-only</code> and they ask why even bother running <code>git fetch</code> when you could just <code>git pull</code>, right? The problem with <code>git pull</code> is that it essentially does two things at once. It fetches the changes from the remote, and then merges (or rebases, depending on the flags) your <code>HEAD</code> with the changes, with the issue being that you don&rsquo;t see what has changed before it begins with the merge.</p> +<p>Automating the merge is fine if it is what you actually wanted to happen, and for this reason I don&rsquo;t think <code>git pull</code> is inherently a bad command. But more often than not I find people get surprised by the result of the pull, as it does something to their local copy that they didn&rsquo;t expect. For that reason alone it might be useful to consider using a combination <code>git fetch</code>, looking at the changes with <code>git log</code> (as we&rsquo;ll see shortly), and then manually merging/rebasing as needed.</p> +<p>By default <code>git fetch</code> will only fetch the tracking remote, but there is also the <code>--all</code> option which will fetch from all remotes.</p> +<ul> +<li><code>alias gf=&quot;git fetch&quot;</code></li> +<li><code>alias gfa=&quot;git fetch --all&quot;</code></li> +</ul> +<h1 id="git-log"><code>git log</code></h1> +<p>Now perhaps one of the commands which forces many people to use GUIs instead of the terminal interface to <code>git</code>. They simply can&rsquo;t find useful information from the default <code>git log</code> output, and I don&rsquo;t blame them. Personally I can&rsquo;t use git on a computer without a proper <code>git log</code> alias as well, and often resort to either searching github for my own <code>git log</code> alias, or just use a GUI.</p> +<p>There are essentially two (or three) parts to making <code>git log</code> usable. One is forcing it to only print out one line per commit, which can either be done using <code>--oneline</code>, or a custom format (as shown shortly) with <code>--pretty</code>. The second is <code>--graph</code>, which visually represents branches and history. The third, and optional, is <code>--all</code>, which shows the history for all branches, not just the past of where <code>HEAD</code> is pointing to.</p> +<p>All of this combined is <code>git log --graph --oneline --all</code>, which when applied to Facebook&rsquo;s React at the time of writing this article looks like this:</p> +<p><img src="https://i.imgur.com/6yiW5Ph.png" alt="git log on react repo"></p> +<p>While this output is very useful and already infinitely better than the default, it does not display the author, when the commit was made, and doesn&rsquo;t give us a way to customize its colors (which might be important if you have a custom color scheme).</p> +<p>Thus I present to you the full version of the <code>--pretty</code> version.</p> +<p><img src="https://i.imgur.com/kvG9Kmr.png" alt="git log pretty on react repo"></p> +<p>The above screenshot was created with the following command:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>git log --all --graph --pretty<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;format:%C(yellow)%h%C(auto)%d%Creset %s %C(white) %C(cyan)%an, %C(magenta)%ar%Creset&#34;</span> +</span></span></code></pre></div><p>It looks complicated, but if you look at it for a few seconds you can see it really isn&rsquo;t. We&rsquo;re just passing in a format string with two different kinds of placeholders. One is the colors, e.g. <code>%C(yellow)</code> or <code>%C(auto)</code>, and the others are the actual content, such as <code>%h</code> or <code>%s</code>. You can certainly customize the command to your liking, and I suggest you look at <code>man git-log</code> in the <code>PRETTY FORMATS</code> section which lists all of the possible format string options.</p> +<p>Because sometimes we want to view the history of the current branch only, and sometimes we want to see all of it at once, we&rsquo;ll resort to two aliases, differing only with the use of <code>--all</code>.</p> +<ul> +<li><code>alias gl='git log --graph --pretty=&quot;format:%C(yellow)%h%C(auto)%d%Creset %s %C(white) %C(cyan)%an, %C(magenta)%ar%Creset&quot;'</code></li> +<li><code>alias gla='gl --all'</code></li> +</ul> +<h2 id="git-merge"><code>git merge</code></h2> +<p>Since branches are an integral part of git, merging branches is equally if not more important. There are two important kinds of merges, fast-forward and with a merge commit. Fast-foward means the current branch set to the ref in which it is being merged into. For example, if we&rsquo;re fast-forward merging <code>master</code> into <code>origin/master</code> and we have no pending changes in the working directory, this is essentially equivalent to running <code>git reset --hard origin/master</code>, as the <code>master</code> label simply changes to a commit further in the history. But sometimes the target ref is not directly ahead and might be lying on a parallel branch, in which case git will create a merge commit that joins the two branches together.</p> +<p>There are three important flags which should be paid attention to:</p> +<ul> +<li><code>--ff</code> (default): tries to perform a fast-forward, and if it can&rsquo;t it will create a merge commit</li> +<li><code>--no-ff</code>: creates a merge commit every single time, even if a fast-forward is possible</li> +<li><code>--ff-only</code>: tries to perform a fast-forward and exits when if it is not possible</li> +</ul> +<p>Most problems arising during git usage come from git doing something that the user did not expect, which is why the first option (<code>--ff</code>) can be quite dangerous. You simply don&rsquo;t know if a fast-forward will happen or if a merge commit will be created unless you examine the history and are certain how fast-forward works.</p> +<p>You might think that git will be able to fast-forward, run <code>git merge --ff</code>, and be surprised by the result and maybe have to revert it, or only realize it later and have even more work to fix. This is why I suggest to never use the default <code>--ff</code> option, but instead be explicit and either use <code>--ff-only</code> or <code>--no-ff</code>.</p> +<p>The benefit is that <code>--ff-only</code> is somewhat safer and thus you can run it without that many worries to basically check if a fast-forward is possible. If it&rsquo;s not, the command will simply fail, and you can decide if you want to run the <code>--no-ff</code> version instead, or maybe re-examine the history and figure out why it failed.</p> +<ul> +<li><code>alias gm=&quot;git merge --no-ff&quot;</code></li> +<li><code>alias gmf=&quot;git merge --ff-only&quot;</code></li> +</ul> +<h2 id="git-push"><code>git push</code></h2> +<p>There&rsquo;s not that much to be said about <code>git push</code>, other than the <code>--tags</code> flag which causes git to push all of the tags to the remote repo, meaning you can do <code>git push --tags origin</code> instead of <code>git push origin &lt;tag name&gt;</code>.</p> +<ul> +<li><code>alias gp=&quot;git push&quot;</code></li> +<li><code>alias gpt=&quot;git push --tags&quot;</code></li> +</ul> +<h2 id="git-reset"><code>git reset</code></h2> +<p>Manipulating the <code>HEAD</code> with <code>git reset</code> is one of the lesser understood commands, and can lead to some potentially dangerous situations. It has multiple modes, the three most useful ones are the following (all examples assume your working dir is clean and you have no pending changes):</p> +<ul> +<li><code>git reset --soft</code>: Moves the <code>HEAD</code>, but leaves the index and working dir as is, meaning if you run <code>git reset --soft HEAD~</code> you&rsquo;ll be in the state right before the last commit you made. Meaning all your changes are already staged.</li> +<li><code>git reset --mixed</code> (default): Resets the index but leaves the working dir as is. As this is the default, the most common use case is to just run <code>git reset</code> without any arguments (which is exactly the same as <code>git reset --mixed</code>), which will unstage all of your changes, but leave the working dir intact.</li> +<li><code>git reset --hard</code>: My favorite variant, and also the most dangerous one. This resets everything to the specified commit, including the working dir. If you run <code>git reset --hard</code> with no target, it will reset all of your staged and unstaged changes to <code>HEAD</code>, essentially saying <em>please discard all the changes I have made</em>. If you specify a target, say <code>git reset --hard HEAD~</code> it means <em>please discard all changes and set <code>HEAD</code> and my current branch to one commit ago</em>, which can be useful if you made a commit and want to discard it completely (just be mindful and don&rsquo;t this if you&rsquo;ve already pushed your changes, or if you&rsquo;re not sure what you&rsquo;re doing in general).</li> +</ul> +<p>One last worthy mention is <code>git reset --patch</code>, which similarly to <code>git add --patch</code> (or <code>-p</code>) will ask you which changes you want to keep staged and which unstaged, and then reset the <code>HEAD</code>.</p> +<p>The respective suggested aliases are:</p> +<ul> +<li><code>alias gr=&quot;git reset&quot;</code></li> +<li><code>alias grp=&quot;git reset --patch&quot;</code></li> +<li><code>alias grh=&quot;git reset --hard&quot;</code></li> +<li><code>alias grsh=&quot;git reset --soft HEAD~&quot;</code></li> +</ul> +<h2 id="git-rebase"><code>git rebase</code></h2> +<p>Similarly to <code>git reset</code>, the <code>git rebase</code> command is one of the lesser understood but more dangerous commands. Some people use it to <em>edit the history</em>, but that&rsquo;s not really what it does. The git history tree is immutable, and we can only ever add new commits to it, which is exactly what <code>git rebase</code> does. It will copy and re-apply existing commits in a different place, possilby modifying them along the way.</p> +<p>Let&rsquo;s go through the example presented in the <code>git rebase</code> manpage (available at <code>man git-rebase</code>):</p> +<blockquote> +<p>Assume the following history exists and the current branch is &ldquo;topic&rdquo;:</p> +<pre><code> A---B---C topic + / + D---E---F---G master +</code></pre> +<p>From this point, the result of either of the following commands:</p> +<pre><code>git rebase master +git rebase master topic +</code></pre> +<p>would be:</p> +<pre><code> A'--B'--C' topic + / + D---E---F---G master +</code></pre> +</blockquote> +<p>At first glance it might seem that <code>git rebase</code> somehow took the commits <code>A</code>, <code>B</code>, and <code>C</code> and moved them over to start at <code>G</code>, but if you look more closely you can see that they were renamed <code>A'</code>, <code>B'</code> and <code>C'</code>. This is very much intentional, because <code>git rebase</code> is not moving the commits, it is simply creating new ones in a different place. The original commits are still in the tree, they are just not visible because nothing is pointing to them. If we were to write down the ref of <code>C</code> prior to doing the rebase, then ran the rebase, and ran <code>git tag REF</code>, it would re-appear in the history as if by magic. That&rsquo;s because it was there all along, <code>git rebase</code> only created its copy on top of <code>G</code>.</p> +<p>The same would happen if we ran <code>git rebase -i HEAD~5</code>, that is interactively rebase last five commits. Sometimes people would do this to squash commits before submitting a pull request. It is important to note that this does not replace those five commits with a new one, it only creates one new commit with the contents of the five, and resets the branch label (and <code>HEAD</code>) to it, making it <em>appear</em> as if the original commits were edited.</p> +<p>While rebase is replaying commits it might run into a conflict, in which case it will stop and ask the user to resolve the conflict. After the conflict is resolved, the rebase can continue with <code>git rebase --continue</code>. As this situation is quite common, we devote an alias to it as well.</p> +<ul> +<li><code>alias grb=&quot;git rebase&quot;</code></li> +<li><code>alias grbc=&quot;git rebase --continue&quot;</code></li> +<li><code>alias grbi=&quot;git rebase -i&quot;</code></li> +</ul> +<p><strong>A word of caution: If you decide to use <code>git rebase</code> on a production codebase, I suggest you take a lookt at <code>git reflog</code> first (<code>man git-reflog</code>) and play around with how different <code>rebase</code> variants get stored in the reflog so you can recover when things go wrong.</strong></p> +<h2 id="git-remote"><code>git remote</code></h2> +<p>Listing and managing remotes is a common practice in any git-controlled project, even if it just means pushing to GitHub (or other). Sometimes we might not be certain where <code>origin</code> is, and that is where <code>git remote -v</code> comes in handy, as it will simply print out the list of remotes.</p> +<ul> +<li><code>alias grv=&quot;git remote -v&quot;</code></li> +</ul> +<h2 id="git-stash"><code>git stash</code></h2> +<p>There&rsquo;s not that many things worthy to mention with <code>git stash</code>, especially since you could accomplish the same using temporary branches and cherry-picking. But sometimes the changes are small enough to warrant the use of <code>git stash</code> instead, and that&rsquo;s why we introduce a few handy aliases:</p> +<ul> +<li><code>alias gst=&quot;git stash&quot;</code></li> +<li><code>alias gstp=&quot;git stash pop&quot;</code></li> +</ul> +<h2 id="git-show"><code>git show</code></h2> +<p>Last command on the list is <code>git show</code>, which simply tells git <em>show me what changed in this commit</em> (including the author, date, and commit message in detail). This might be useful both when checking what the last commit was (either <code>git show HEAD</code> or just <code>git show</code> without an argument), or when looking at a particular commit in the past.</p> +<p>The alias <code>gw</code> might not be what you immediately think of, but since other <code>gs</code>-prefixed ones are taken, it is at least somewhat phoentically resemblant of the command itself.</p> +<ul> +<li><code>alias gw=&quot;git show&quot;</code></li> +</ul> +<h2 id="conclusion">Conclusion</h2> +<p>If you&rsquo;ve read this far I hope you learned at least a thing or two. Git is a massive tool with hundreds of useful flags and sub-commands and there are definitely times where having that one extra trick up your sleeve can save you hours of pain. <strong>If you have any tips, suggestions, corrections, or feedback, please do leave a comment below or hit me up on twitter. I&rsquo;ll be sure to reply to each and every comment.</strong></p> +<p>Here is a complete list of aliases mentioned in the article, ready to be copy-pasted into your <code>~/.bashrc</code> or <code>~/.zshrc</code> or wherever else you store your aliases (sorry <code>fish</code> users).</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> s<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git status -sb&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> ga<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git add&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gau<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git add -u&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gap<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git add -p&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gb<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git branch&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gba<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git branch --all&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gc<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git commit -v&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gca<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git commit -v -a&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gcam<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;gca --amend&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gch<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git cherry-pick&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gco<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git checkout&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> d<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git diff -M&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gdc<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git diff -M --cached&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gf<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git fetch&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gfa<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git fetch --all&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gl<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#39;git log --graph --pretty=&#34;format:%C(yellow)%h%C(auto)%d%Creset %s %C(white) %C(cyan)%an, %C(magenta)%ar%Creset&#34;&#39;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gla<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#39;gl --all&#39;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gm<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git merge --no-ff&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gmf<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git merge --ff-only&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gp<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git push&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gpt<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git push --tags&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gr<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git reset&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> grp<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git reset --patch&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> grh<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git reset --hard&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> grsh<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git reset --soft HEAD~&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> grb<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git rebase&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> grbc<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git rebase --continue&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> grbi<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git rebase -i&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> grv<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git remote -v&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gst<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git stash&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gstp<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git stash pop&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">alias</span> gw<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;git show&#34;</span> +</span></span></code></pre></div> + + + + Eigenvalues and Eigenvectors: Basic Properties + https://blog.jakuba.net/eigenvalues-and-eigenvectors/ + Sat, 08 Dec 2018 01:44:08 +0100 + + https://blog.jakuba.net/eigenvalues-and-eigenvectors/ + <p>Eigenvalues and eigenvectors of a matrix $\boldsymbol A$ tell us a lot about +the matrix. On the other hand, if we know our matrix $\boldsymbol A$ is somehow +special (say symmetric) it will tell us some information about how its +eigenvalues and eigenvectors look like.</p> +<p>Let us begin with a definition. Given a matrix $\boldsymbol A$, the vector $x$ is an eigenvector +of $\boldsymbol A$ and has a corresponding eigenvalue $\lambda$, if</p> +<p>$$ +\boldsymbol A \boldsymbol x = \lambda \boldsymbol x. +$$</p> +<p>The eigenvectors of a matrix $\boldsymbol A$ are exactly those vectors which +when transformed by the mapping defined by $\boldsymbol A$ are only scaled by +$\lambda$, but their direction does not change.</p> +<h2 id="eigenvalues-and-eigenvectors-of-a-projection-matrix">Eigenvalues and eigenvectors of a projection matrix</h2> +<p>To understand what eigenvectors are and how they behave, let us consider a +projection matrix $\boldsymbol P$. What are $x$&rsquo;s and $\lambda$&rsquo;s for a +projection matrix?</p> +<p>The key property we&rsquo;ll use is $\boldsymbol P^2 = \boldsymbol P$. This is +because when we project a vector $x$ onto a plane to get $\hat x$, that is +$\boldsymbol P x = \hat x$, we would expect that projecting $\hat x$ again to +do nothing, since it already lies in the plane, that is</p> +<p>$$ +\hat x = \boldsymbol P \hat x = \boldsymbol P (\boldsymbol P x) = (\boldsymbol +P \boldsymbol P) x = \boldsymbol P^2 x. +$$</p> +<p>Now thinking about eigenvectors as those vectors which don&rsquo;t change direction +when a projection matrix is applied, we can deduce two cases:</p> +<ul> +<li>Any $x$ already in the plane: $\boldsymbol P x = x, \lambda = 1$.</li> +<li>Any $x$ perpendicular to the plane: $\boldsymbol P x = 0 x, \lambda = 0$.</li> +</ul> +<p>As a result, a projection matrix $\boldsymbol P$ has two eigenvalues, $\lambda += 0$ and $\lambda = 1$, and two sets of eigenvectors. Those that lie in the +projection plane, and those that are perpendicular to it.</p> +<h2 id="eigenvalues-of-a-2-times-2-permutation-matrix">Eigenvalues of a $2 \times 2$ permutation matrix</h2> +<p>One more small example, consider a $2 \times 2$ permutation matrix +$\boldsymbol A = \begin{pmatrix}0 &amp; 1 \\ 1 &amp; 0 \end{pmatrix}$.</p> +<p>We can find the eigenvectors straight away, at least the first one, which is +simply $x = (1\ 1)^T$, since $\boldsymbol A x = x$, and so its corresponding +eigenvalue is $\lambda = 1$.</p> +<p>If we think a little harder, we can guess the second eigenvector to be +$x = (-1\ 1)^T$, since $\boldsymbol A = -x$ with an eigenvalue $\lambda = -1$.</p> +<h2 id="computing-eigenvalues-and-eigenvectors">Computing eigenvalues and eigenvectors</h2> +<p>We can re-arrange the terms in our definition to get a direct way to compute +eigenvalues and eigenvectors of a matrix $\boldsymbol A$. Simply move $\lambda x$ +to the left</p> +<p>$$ +\begin{aligned} +\boldsymbol A x &amp;= \lambda x \\\\ +(\boldsymbol A - \lambda \boldsymbol I) x &amp;= 0 \\\\ +\end{aligned} +$$</p> +<p>and then notice that $\boldsymbol A - \lambda \boldsymbol I$ must be singular, +because $x$ lies in its nullspace. We know that singular matrices have a zero +determinant, and we can use this to compute the eigenvalues $\lambda$ simply by +writing</p> +<p>$$ +\det (\boldsymbol A - \lambda \boldsymbol I) = 0. +$$</p> +<p>This is called the <strong>characteristic equation</strong>. The equation $det(\boldsymbol A</p> +<ul> +<li>\lambda \boldsymbol I) = 0$ gives us a polynomial of degree $n$, which we can +use to find $n$ solutions $\lambda$. These need not be different, and can even +be complex numbers. But once we obtain the $\lambda$&rsquo;s we can plug them back into</li> +</ul> +<p>$$ +(\boldsymbol A - \lambda \boldsymbol I) x = 0 +$$</p> +<p>and one by one obtain their corresponding eigenvectors $x$.</p> +<h2 id="eigenvalues-and-eigenvectors-of-an-upper-triangular-matrix">Eigenvalues and eigenvectors of an upper triangular matrix</h2> +<p>For a triangular matrix, the determinant is just the diagonal</p> +<p>$$ +det(\boldsymbol A) = \prod_{i=1}^n \boldsymbol A_{ii} +$$</p> +<p>which means solving the characteristic equation of $\boldsymbol A$ +simply amounts to multiplying out the diagonal</p> +<p>$$ +det(\boldsymbol A - \lambda \boldsymbol I) = \prod_{i=1}^n (\boldsymbol A - \lambda \boldsymbol I)_{ii}, +$$</p> +<p>which gives us a factored polynomial $(\boldsymbol A_{11} - \lambda)(\boldsymbol A_{22} - +\lambda)\ldots(\boldsymbol A_{nn} - \lambda)$, from which we immediately see that the +eigenvalues are the diagonal elements.</p> +<h2 id="diagonalization-boldsymbol-s-1-boldsymbol-a-boldsymbol-s--boldsymbol-lambda">Diagonalization $\boldsymbol S^{-1} \boldsymbol A \boldsymbol S = \boldsymbol \Lambda$</h2> +<p>Suppose we have $n$ linearly independent eigenvectors of $\boldsymbol A$. Put +them int the columns of $\boldsymbol S$. We now write</p> +<p>$$ +\def\vertbar{{\rule[-1ex]{0.5pt}{2.5ex}}} +$$</p> +<p>$$ +\boldsymbol A \boldsymbol S = A \begin{bmatrix} +\vertbar &amp; \vertbar &amp; &amp; \vertbar \\\\ +x_1 &amp; x_2 &amp; \cdots &amp; x_n \\\\ +\vertbar &amp; \vertbar &amp; &amp; \vertbar +\end{bmatrix} = \begin{bmatrix} +\vertbar &amp; \vertbar &amp; &amp; \vertbar \\\\ +\lambda_1 x_1 &amp; \lambda_2 x_2 &amp; \cdots &amp; \lambda_n x_n \\\\ +\vertbar &amp; \vertbar &amp; &amp; \vertbar +\end{bmatrix} = \boldsymbol S \boldsymbol \Lambda +$$</p> +<p>where $\boldsymbol \Lambda$ is a diagonal matrix of eigenvalues. Thus we get +$\boldsymbol A \boldsymbol S = \boldsymbol S \boldsymbol \Lambda$. If we have +$n$ independent eigenvectors in $\boldsymbol A$, we also get</p> +<p>$$ +\begin{align} +\boldsymbol A \boldsymbol S &amp;= \boldsymbol S \boldsymbol \Lambda \\\\ +\boldsymbol S^{-1} \boldsymbol A \boldsymbol S = \boldsymbol \Lambda \\\\ +\boldsymbol A &amp;= \boldsymbol S \boldsymbol \Lambda \boldsymbol S^{-1} +\end{align} +$$</p> +<p>The matrix $\boldsymbol A$ is sure to have $n$ independent eigenvectors (and be +diagonalizable) if all the $\lambda$&rsquo;s are different (no repeated $\lambda$&rsquo;s). +Repeated eigenvalues mean $\boldsymbol A$ may or may not have $n$ independent +eigenvectors.</p> +<p>Proof (ref G. Strang, Introduction to LA): Suppose $c_1 + x_1 + c_2 x_2 = 0$. Multiply by $\boldsymbol A$ to +find $c_1 \lambda_1 x_1 + c_2 \lambda_2 x_2 = 0$. Multiply by $\lambda_2$ +to find $c_1 \lambda_2 x_1 + c_2 \lambda_2 x_2 = 0$. Now subtracting +these two equations gives us</p> +<p>$$ +(\lambda_1 - \lambda_2) c_1 x_1 = 0. +$$</p> +<p>Since $\lambda_1 \neq \lambda_2$ and $x_1 \neq 0$, we conclude $c_1 = 0$. +We can derive $c_2 = 0$ the same way. Since $c_1 = c_2 = 0$ are the only +coefficients for which $c_1 x_1 + c_2 x_2 = 0$, we see that $x_1$ and +$x_2$ are linearly independent.</p> +<p>The same argument can be extended to $n$ eigenvectors and eigenvalues.</p> +<h2 id="sum-of-eigenvalues-equlas-the-trace">Sum of eigenvalues equlas the trace</h2> +<p>Another very useful fact is that the sum of the eigenvalues equals +the sum of the main diagonal (called the <strong>trace</strong> of $\boldsymbol A$), +that is</p> +<p>$$ +\lambda_1 + \lambda_2 + \ldots + \lambda_n = \boldsymbol A_{11} + +\boldsymbol A_{22} + \ldots + \boldsymbol A_{nn} = Tr(\boldsymbol A). +$$</p> +<p>To prove this we&rsquo;ll first show that $Tr(\boldsymbol A \boldsymbol B) = +Tr(\boldsymbol B \boldsymbol A)$.</p> +<p>To get a single element on the diagonal of $\boldsymbol A \boldsymbol B$ we +simply write</p> +<p>$$ +(\boldsymbol A \boldsymbol B)_{jj} = \sum_{k} \boldsymbol A_{jk} \boldsymbol +B_{kj} +$$</p> +<p>and to get the trace we just sum over all possible $j$ as</p> +<p>$$ +Tr(\boldsymbol A \boldsymbol B) = \sum_{j} \sum_{k} \boldsymbol A_{jk} +\boldsymbol B_{kj}. +$$</p> +<p>On the other hand, the $k$-th element on the diagonal of $\boldsymbol B +\boldsymbol A$ is</p> +<p>$$ +(\boldsymbol B \boldsymbol A)_{kk} = \sum_{j} \boldsymbol B_{kj} \boldsymbol +A_{jk} +$$</p> +<p>and the trace $Tr(\boldsymbol B \boldsymbol A)$ is</p> +<p>$$ +Tr(\boldsymbol B \boldsymbol A) = \sum_{k} \sum_{j} \boldsymbol B_{kj} +\boldsymbol A_{jk}. +$$</p> +<p>But since we can swap the order of summation and also swap the order of +multiplication, we get</p> +<p>$$ +Tr(\boldsymbol B \boldsymbol A) = \sum_{k} \sum_{j} \boldsymbol B_{kj} +\boldsymbol A_{jk} = \sum_{j} \sum_{k} \boldsymbol A_{jk} \boldsymbol +B_{kj} = Tr(\boldsymbol A \boldsymbol B). +$$</p> +<p>Now consider we have $n$ different eigenvalues. We can diagonalize the matrix</p> +<p>$$ +\boldsymbol S^{-1} \boldsymbol A \boldsymbol S = \boldsymbol \Lambda +$$</p> +<p>where $\boldsymbol \Lambda$ is a diagonal matrix of eigenvalues of $\boldsymbol +A$. Using our trace trick we can write</p> +<p>$$ +Tr(\boldsymbol \Lambda) = Tr(\boldsymbol S^{-1} \boldsymbol A \boldsymbol S) = +Tr((\boldsymbol S^{-1} \boldsymbol A) \boldsymbol S) = Tr(\boldsymbol S (\boldsymbol S^{-1} \boldsymbol A)) = +Tr((\boldsymbol S \boldsymbol S^{-1}) \boldsymbol A) = Tr(\boldsymbol I \boldsymbol A) = Tr(\boldsymbol A) +$$</p> +<p>and thus the sum of eigenvalues is equal the trace of $\boldsymbol A$. We&rsquo;ve +only shown this for the case of $n$ different eigenvalues. This property does +hold in general, but requires some properties we haven&rsquo;t proven yet (Jordan +normal form), and thus we skip the rest of the proof.</p> +<p>If you&rsquo;re interested, check out <a href="http://www.applet-magic.com/eigenvaluestrace.htm">the following +article</a> which shows the +whole proof, and possibly <a href="https://en.wikipedia.org/wiki/Jordan_normal_form">the Wikipedia article on Jordan normal +form</a>.</p> +<h2 id="powers-of-a-matrix">Powers of a matrix</h2> +<p>If $\boldsymbol A x = \lambda x$, then we multiply by $\boldsymbol A$ and get</p> +<p>$$ +\boldsymbol A^2 x = \lambda \boldsymbol A x = \lambda^2 x. +$$</p> +<p>Continuing</p> +<p>$$ +\boldsymbol A^2 = \boldsymbol S \boldsymbol \Lambda \boldsymbol S^{-1} +\boldsymbol S \boldsymbol \Lambda \boldsymbol S^{-1} = \boldsymbol S \boldsymbol \Lambda^2 \boldsymbol S^{-1} +$$</p> +<p>or in general</p> +<p>$$ +\boldsymbol A^k = \boldsymbol S \boldsymbol \Lambda^k \boldsymbol S^{-1}. +$$</p> +<p>Theorem: $\boldsymbol A^k \rightarrow 0$ as $k \rightarrow \infty$ if all +$|\lambda_i| &lt; 1$.</p> +<h2 id="more-properties">More properties</h2> +<p>$\boldsymbol A$ and $\boldsymbol B$ share the same $n$ independent +eigenvectors if and only if $\boldsymbol A \boldsymbol B = \boldsymbol B +\boldsymbol A$.</p> +<p>This is true because $\boldsymbol A \boldsymbol B x = \lambda \beta x$ and +$\boldsymbol B \boldsymbol A x = \lambda \beta x$ since</p> +<p>$$ +\boldsymbol A \boldsymbol B x = \boldsymbol A \beta x = \beta \boldsymbol A x = \beta \lambda x. +$$</p> +<p><strong>But this only holds if $\boldsymbol A$ and $\boldsymbol B$ share the same eigenvectors!</strong></p> +<p>One last interesting fact we can show is what happens to the eigenvalues when +we add a constant $c$ to the matrix $\boldsymbol A$. The proof is rather trivial, +if $\boldsymbol A x = \lambda x$, then</p> +<p>$$ +(\boldsymbol A + c) x = (\boldsymbol A + c \boldsymbol I) x = (\lambda + c) x. +$$</p> +<p>Adding a constant to a matrix causes its eigenvalues to increase by exactly +that constant.</p> +<h2 id="references-and-visualizations">References and visualizations</h2> +<ul> +<li><a href="http://math.mit.edu/~gs/linearalgebra/ila0601.pdf">Introduction to Linear Algebra, Gilbert Strang</a></li> +<li><a href="http://setosa.io/ev/eigenvectors-and-eigenvalues/">setosa.io</a></li> +<li><a href="https://the-learning-machine.com/article/machine-learning/linear-algebra">The Learning Machine</a></li> +</ul> + + + + + Mixture of Categoricals and Latent Dirichlet Allocation (LDA) + https://blog.jakuba.net/mixture-of-categoricals-and-latent-dirichlet-allocation-lda/ + Wed, 05 Dec 2018 21:50:26 +0100 + + https://blog.jakuba.net/mixture-of-categoricals-and-latent-dirichlet-allocation-lda/ + <p>Now that we&rsquo;ve worked through the <a href="https://blog.jakuba.net/posterior-predictive-distribution-for-the-dirichlet-categorical-model/">Dirichlet-Categorical model in quite a bit of detail</a> +we can move onto document modeling.</p> +<p>Let us begin with a very simple document model in which we consider only a single distribution +over words across all documents. We have the following variables:</p> +<ul> +<li>$N_d$: number of words in $d$-th document.</li> +<li>$D$: number of documents.</li> +<li>$M$: number of words in the dictionary.</li> +<li>$\boldsymbol\beta = (\beta_1,\ldots,\beta_M)$: probabilities of each word.</li> +<li>$w_{nd} \sim Cat(\boldsymbol\beta)$: $n$-th word in $d$-th document.</li> +<li>$I(w_{nd} = m)$: indicator variable saying that the $n$-th word in the $d$-th document is $m$.</li> +</ul> +<p>To summarize, there is only one random variable $w_{nd}$, which is observed +and has a Categorical distribution with a parameter $\boldsymbol\beta$. We can +fit this model <a href="https://blog.jakuba.net/maximum-likelihood-for-multinomial-distribution/">using maximum likelihood estimation (MLE) directly as we&rsquo;ve +shown before</a>, +that is</p> +<p>$$ +\beta_m = \frac{c_m}{N} +$$</p> +<p>where $c_m$ is the number of occurences of the $m$-th word and $N$ is the +total number of word occurences in all documents. It is important to distinguish +between $M$ and $N$, as $M$ is the number of words in the dictionary, that is unique words, +and $N$ is the sum of all the counts. Specifically:</p> +<p>$$ +\begin{align} +N &amp;= \sum_{d=1}^D N_d \\\\ +c_m &amp;= \sum_{d=1}^D \sum_{n=1}^{N_d} I(w_{nd} = m) +\end{align} +$$</p> +<p>In this case $c_m$ sums over document, and in each document it sums up all the +occurences of $m$-th word, that is summing over all indexes in that document +and adding $1$ for each occurence of $m$.</p> +<p>There are downsides to this simple model though. Sharing one $\boldsymbol\beta$ +between all documents means that all documents have the same distribution of words. +What we would like instead is allow each document to be about a different topic, +and have a different distribution of words for each topic.</p> +<h2 id="mixture-of-categoricals">Mixture of Categoricals</h2> +<p>We&rsquo;ll modify our model to allow it to have multiple topics, each of which will +have its own categorical distribution on words. We introduce a second random +variable $z_d \sim Cat(\boldsymbol\theta)$ where $\boldsymbol\theta$ is a +vector of topic probabilities.</p> +<ul> +<li>$z_d$: assigns document $d$ to one of the $K$ categories.</li> +<li>$\theta_k = p(z_d = k)$: probability that a document $d$ is assigned to category $k$.</li> +<li>$w_{nd} | z_d \sim Cat(\boldsymbol\beta_{z_d})$: distribution over words +at $n$-th position in document $d$ given we have observed its topic $z_d$.</li> +</ul> +<p>A small note, the distribution of $w_{nd}$ actually depends on the document +$d$ (on its topic), while in the previous document it remained constant +throughout. We can write this model in its generative process specification +as follows:</p> +<p>$$ +\begin{align} +z_d &amp;\sim Cat(\boldsymbol\theta) \\\\ +w_{nd} | z_d &amp;\sim Cat(\boldsymbol\beta_{z_d}) +\end{align} +$$</p> +<p>In order to allow our model to capture different topics, we introduced a set of +latent (hidden) variables $z_d$. Now the problem becomes, how do we perform +maximum likelihood estimation with these hidden variables? Let us write out the likelihood</p> +<p>$$ +\begin{align} +p(\boldsymbol w | \boldsymbol\theta, \boldsymbol\beta) +&amp;= \prod_{d=1}^D p(\boldsymbol w_d | \boldsymbol\theta, \boldsymbol\beta) \qquad\text{expanding the marginal}\\\\ +&amp;= \prod_{d=1}^D \sum_{k=1}^K p(\boldsymbol w_d, z_d = k | \boldsymbol\theta, \boldsymbol\beta) \\\\ +&amp;= \prod_{d=1}^D \sum_{k=1}^K p(\boldsymbol w_d | z_d = k, \boldsymbol\beta) p(z_d = k | \boldsymbol\theta) \\\\ +&amp;= \prod_{d=1}^D \sum_{k=1}^K \left( \prod_{n=1}^{N_d} p(w_{nd} | z_d = k, \boldsymbol\beta) \right) p(z_d = k | \boldsymbol\theta) \\\\ +\end{align} +$$</p> +<p>We cannot easily optimize through the marginalization, and even if we were to +take the log likelihood</p> +<p>$$ +\log p(\boldsymbol w | \boldsymbol\theta, \boldsymbol\beta) += \sum_{d=1}^D \log \left( \sum_{k=1}^K \left( \prod_{n=1}^{N_d} p(w_{nd} +| z_d = k, \boldsymbol\beta) \right) p(z_d = k | \boldsymbol\theta) \right) +$$</p> +<p>we run into a problem with a sum inside a log, that is $\sum \log \left(\sum +\ldots \right)$, and we cannot move the log inside the sum, and solving the +equation analytically is not possible, at least in the general form. This is +where the Expectation-Maximization (EM) algorithm comes in and allows us to +find a local optimum using MLE. But for now we&rsquo;ll move onto the bayesian +approach and cover EM in a separate article in more depth.</p> +<h2 id="bayesian-mixture-of-categoricals">Bayesian Mixture of Categoricals</h2> +<p>To move from a point estimate of the EM to a fully bayesian treatment, we&rsquo;ll +introduce a prior distribution over the parameters $\boldsymbol\theta$ and +$\boldsymbol\beta$. Since they are both parameters of a Categorical +distribution, it is of no surprise that our priors will be a Dirichlet +distribution.</p> +<p>The generative model specification then becomes</p> +<p>$$ +\begin{align} +\boldsymbol\theta \sim Dir(\boldsymbol\alpha) \\\\ +\boldsymbol\beta_k \sim Dir(\boldsymbol\gamma) \\\\ +z_d | \boldsymbol\theta \sim Cat(\boldsymbol\theta) \\\\ +w_{nd} | z_d,\boldsymbol\beta_{z_d} \sim Cat(\boldsymbol\beta_{z_d}) +\end{align} +$$</p> +<p>where $\boldsymbol\alpha$ is the hyperparameter over topic probabilities, while +$\boldsymbol\gamma$ is the hyperparameter over dictionary probabilities.</p> +<p>Now that we have our priors, we could compute a MAP estimate using EM, but we&rsquo;ll +instead go one step further, extend our model to Latent Dirichlet allocation (LDA), +and then cover full bayesian inference using Gibbs sampling.</p> +<h2 id="latent-dirichlet-allocation-lda">Latent Dirichlet Allocation (LDA)</h2> +<p>One limitation of the mixture of categoricals model is that words in each +document are drawn only from one specific topic. The problem is when we have +documents that span more than one topic, in which case we need to learn a +mixture of those topics. We also allow the distribution of topics to vary +across documents.</p> +<p>In LDA, each document becomes a mixture of topics, but each word is still drawn +from one of those topics. We don&rsquo;t need to introduce new random variables, +we&rsquo;ll simply create more of what we have. In the mixture of categoricals we had +$z_d$ be a distribution over possible topics of the $d$-th document. We +replace it with $z_{nd}$ which becomes a distribution over possible topics of +the $n$-th word in $d$-th document. We also introduce $\boldsymbol\theta_d$, +which is a distribution over topics for the $d$-th document.</p> +<p>A generative model then becomes:</p> +<p>$$ +\begin{align} +\boldsymbol\theta_d &amp;\sim Dir(\boldsymbol\alpha) \\\\ +\boldsymbol\beta_k &amp;\sim Dir(\boldsymbol\gamma) \\\\ +z_{nd} | \boldsymbol\theta_d &amp;\sim Cat(\boldsymbol\theta_d) \\\\ +w_{nd} | z_{nd}, \boldsymbol\beta_{z_d} &amp;\sim Cat(\boldsymbol\beta_{z_d}) \\\\ +\end{align} +$$</p> +<p>We can view this generative process as a sequential recipe for generating a set +of documents:</p> +<ul> +<li>For each document $d$, draw $\boldsymbol\theta_d$ from the prior +distribution $Dir(\boldsymbol\alpha)$.This is the parameter for our +Categorical distribution over topics.</li> +<li>For each topic $k$, draw $\boldsymbol\beta_k$ from the prior +$Dir(\boldsymbol\gamma)$. This is the parameter for our Categorical +distribution over words in that topic.</li> +<li>For each $z_{nd}$, that is each word position $n$ in a document $d$ draw its +topic from $Cat(\boldsymbol\theta_d)$. This allows us to have each word in +a document drawn from a different topic.</li> +<li>Draw each word $w_{nd}$ from its corresponding $Cat(\boldsymbol\beta_{z_{nd}})$.</li> +</ul> +<p>The critical part here is in the last step, where each word at position $n$ in +document $d$ is drawn from $Cat(\boldsymbol\beta_{z_{nd}})$. The parameter +$\boldsymbol\beta_{z_{nd}}$ of the distribution of $w_{nd}$ depends on +$z_{nd}$, that is $p(w_{nd} | z_{nd})$. Even though each document $d$ has +only a single distribution over topics $Cat(\boldsymbol\theta_d)$, we draw a topic +$z_{nd}$ for each word position $n$ in the document $d$.</p> +<p>We can think of $z_{nd}$ as defining a distribution over words at position $n$ +in document $d$. The problem with viewing it directly as a distribution is +that in such view we ignore the topics and don&rsquo;t share word probabilities among +different positions from the same topic. That&rsquo;s why we keep a separate set of +random variables $\boldsymbol\beta_k$, which define the distribution over +words in a topic $k$, and $z_{nd}$ simply acts as an index into one of those +$\boldsymbol\beta_k$.</p> +<p>This allows us to draw the topic of each position in each document independently, +while sharing the probabilities of words within the same topic between document.</p> +<p>Just to summarize, we have the following count constants:</p> +<ul> +<li>$D$ is the number of documents.</li> +<li>$N_d$ is the number of words in document $d$.</li> +<li>$K$ is the number of topics.</li> +</ul> +<p>and the following random variables:</p> +<ul> +<li>One hyperparameter $\boldsymbol\alpha$ for the prior distribution on topics +for each document.</li> +<li>One hyperparameter $\boldsymbol\gamma$ for the prior distribution on words in +each topic.</li> +<li>A set of $D$ (number of documents) parameters $\boldsymbol\theta_{1:D}$ for our +per-document topic distribution.</li> +<li>A set of $K$ parameters $\boldsymbol\beta_{1:K}$ for our per-topic word distribution.</li> +<li>A set of $N \times D$ random variables $z_{nd}$ for each position in each +document signifying the topic of a word at that position.</li> +<li>A set of $N \times D$ random variables $w_{nd}$ representing the actual word +at a given position in each document, drawn from the $z_{nd}$-th topic.</li> +</ul> +<h2 id="inference-in-lda">Inference in LDA</h2> +<p>Similarly to the Mixture of Categoricals, if we wanted to compute the posterior +over our parameters $\boldsymbol\beta_{1:K}$ and $\boldsymbol\theta_{1:D}$ given we +observed words $z_{nd}$, we&rsquo;d need to marginalize out the latent variables +$z_{nd}$. Let us write out the posterior first:</p> +<p>$$ +p(\boldsymbol\beta, \boldsymbol\theta, \boldsymbol z | \boldsymbol w, \alpha, \gamma) = +\frac{p(\boldsymbol\beta, \boldsymbol\theta, \boldsymbol z, \boldsymbol w | \alpha, \gamma)}{ +p(\boldsymbol w | \alpha, \gamma) +} +$$</p> +<p>where</p> +<p>$$ +p(\boldsymbol\beta, \boldsymbol\theta, \boldsymbol z, \boldsymbol w | \gamma, \alpha) += \prod_{k=1}^K p(\boldsymbol\beta_k | \gamma) \prod_{d=1}^D \left( +p(\boldsymbol\theta_d | \alpha) +\prod_{n=1}^{N_d} \left( p(z_{nd} | \boldsymbol\theta_d) p(w_{nd} | \boldsymbol\beta, z_{nd}) \right) +\right) +$$</p> +<p>and the normalization constant $p(\boldsymbol w | \alpha, \gamma)$ written out as</p> +<p>$$ +p(\boldsymbol w | \alpha, \gamma) = \int \int \sum_{z_{id}} \prod_{d=1}^D \prod_{k=1}^K \prod_{n=1}^{N_d} +p(z_{nd} | \boldsymbol\theta_d) p(\boldsymbol\theta_d | \alpha) p(w_{nd} | \boldsymbol\beta, z_{nd}) +p(\boldsymbol\beta_k | \gamma)\ d\boldsymbol\beta_k\ d\boldsymbol\theta_d +$$</p> +<p>is intractable, since we&rsquo;d need to marginalize out the latent variables +$z_{nd}$. If every document had $N$ words, this means $K^N$ configurations per +document.</p> +<p>Although the posterior is intractable for exact inference, we can use many approximate +inference algorithms, e.g. Markov-Chain Monte Carlo and variational inference. In the next +article we&rsquo;ll see how to apply Gibbs sampling to LDA.</p> +<h2 id="references">References</h2> +<ul> +<li><a href="http://mlg.eng.cam.ac.uk/teaching/4f13/1819/">Probabilistic Machine Learning 4f13 Michaelmas 2018, +Cambridge</a></li> +<li><a href="http://www.jmlr.org/papers/volume3/blei03a/blei03a.pdf">Latent Dirichlet Allocation, David Blei, Andrew Ng, Michael +Jordan</a></li> +</ul> + + + + + Posterior Predictive Distribution for the Dirichlet-Categorical Model (Bag of Words) + https://blog.jakuba.net/posterior-predictive-distribution-for-the-dirichlet-categorical-model/ + Tue, 04 Dec 2018 14:22:58 +0100 + + https://blog.jakuba.net/posterior-predictive-distribution-for-the-dirichlet-categorical-model/ + <p>In the <a href="https://blog.jakuba.net/maximum-likelihood-for-multinomial-distribution/">previous article we derived a maximum likelihood estimate (MLE) for the +parameters of a Multinomial distribution</a>. This time +we&rsquo;re going to compute the full posterior of the Dirichlet-Categorical model as +well as derive the posterior predictive distribution. This will close our +exploration of the Bag of Words model.</p> +<h2 id="likelihood">Likelihood</h2> +<p>Similarly as in the previous article, our likelihood will be defined by a +Multinomial distribution, that is</p> +<p>$$ +p(D|\boldsymbol\pi) \propto \prod_{i+1}^m \pi_i^{x_i}. +$$</p> +<p>Since the Dirichlet distribution is a conjugate prior to the Multinomial, we +can omit the normalization constants as we will be able to infer them +afterwards from the unnormalized posterior parameters. Knowing that the +posterior is again a Dirichlet distribution saves us a lot of tedious work.</p> +<h2 id="prior">Prior</h2> +<p>Much like the model name would suggest, our prior will be the Dirichlet distribution, +which defines an $m-dimensional$ probability simplex over the Multinomial&rsquo;s parameters. +The prior has the form</p> +<p>$$ +p(\boldsymbol\pi|\boldsymbol\alpha) = \frac{1}{B(\boldsymbol\alpha)} +\prod_{i=1}^m \pi_i^{\alpha_i - 1}. +$$</p> +<h2 id="posterior">Posterior</h2> +<p>Multiplying the likelihood by the prior will directly give us the shape of the posterior +because of the conjugacy. We don&rsquo;t have to care about the normalizing constant. As a result, we obtain</p> +<p>$$ +\begin{align} +p(\boldsymbol\pi | D) &amp;\propto p(D|\boldsymbol\pi) p(\boldsymbol\pi | \boldsymbol\alpha) \\\\ +&amp;= \prod_{i=1}^m \pi_i^{x_i} \prod_{i=1}^m \pi_i^{\alpha_i - 1} \\\\ +&amp;\propto \prod_{i=1}^m \pi_i^{\alpha_i + x_i - 1} \\\\ +&amp;\propto Dir(\boldsymbol\pi | \alpha_1 + x_1, \alpha_2 + x_2, \ldots, \alpha_m + x_m) +\end{align} +$$</p> +<p>We can write this more succintly as $Dir(\boldsymbol\pi | \boldsymbol\alpha</p> +<ul> +<li>\boldsymbol x)$ where $x$ is the vector of counts of the observed data $D$.</li> +</ul> +<h2 id="map-estimate-of-the-parameters">MAP estimate of the parameters</h2> +<p>Since we have our posterior, we can take a small detour and compute the +maximum-aposteriori (MAP) estimate of the parameters, which is simply the mode +of the posterior (its maximum). We can do this similarly to the <a href="https://blog.jakuba.net/maximum-likelihood-for-multinomial-distribution/">previous +article</a> and use lagrange multipliers to enforce the constraint that $\sum_{i=1}^m</p> +<blockquote> +<p>\pi_i = 1$. Since the Dirichlet distribution is again of the exponential family, +we differentiate the log posterior, which in turn is the log likelihood plus the log prior</p> +</blockquote> +<p>$$ +\log p(\boldsymbol\pi | D) \propto \log p(D | \boldsymbol\pi) + \log p(\boldsymbol\pi | \boldsymbol\alpha). +$$</p> +<p>The lagrangian than has the following form</p> +<p>$$ +L(\boldsymbol\pi, \lambda) = \sum_{i=1}^m x_i \log \pi_i + \sum_{i=1}^m +(\alpha_i - 1) \log \pi_i + \lambda \left( 1 - \sum_{i=1}^m \pi_i \right). +$$</p> +<p>Same as before, we differentiate the lagrangian with respect to $\boldsymbol\pi_i$</p> +<p>$$ +\frac{\partial}{\partial\pi_i} L(\boldsymbol\pi, \lambda) = +\frac{x_i}{\pi_i} + \frac{\alpha_i - 1}{\pi_i} - \lambda = \frac{x_i + \alpha_i</p> +<ul> +<li>1}{\pi_i} - \lambda +$$</li> +</ul> +<p>and set it equal to zero</p> +<p>$$ +\begin{align} +0 &amp;= \frac{x_i + \alpha_i - 1}{\pi_i} - \lambda \\\\ +\lambda &amp;= \frac{x_i + \alpha_i - 1}{\pi_i} \\\\ +\pi_i &amp;= \frac{x_i + \alpha_i - 1}{\lambda}. +\end{align} +$$</p> +<p>Finally, we can apply the same trick as before and solve for $\lambda$</p> +<p>$$ +\begin{align} +\pi_i &amp;= \frac{x_i + \alpha_i - 1}{\lambda} \\\\ +\sum_{i=1}^m \pi_i &amp;= \sum_{i=1}^m \frac{x_i + \alpha_i - 1}{\lambda} \\\\ +1 &amp;= \sum_{i=1}^m \frac{x_i + \alpha_i - 1}{\lambda} \\\\ +\lambda &amp;= \sum_{i=1}^m \left( x_i + \alpha_i - 1 \right) \\\\ +\lambda &amp;= n - m + \sum_{i=1}^m \alpha_i. +\end{align} +$$</p> +<p>We can plug this back in to get the MAP estimate</p> +<p>$$ +\pi_i = \frac{x_i + \alpha_i - 1}{n + \left(\sum_{i=1}^m \alpha_i \right) - m}. +$$</p> +<p>Comparing this with the MLE estimate, which was</p> +<p>$$ +\pi_i = \frac{x_i}{n} +$$</p> +<p>we can see the concentration parameter $\boldsymbol\alpha$ affects the +probability. If we were to set a uniform prior with $\alpha_i=1$, we would +recover the original MLE estimate.</p> +<h2 id="posterior-predictive">Posterior predictive</h2> +<p>The posterior predictive distribution give us a distribution over the possible +outcomes while taking into account our uncertainty in the parameters given by +the posterior distribution. For a general model with an outcome $X$ and a parameter +vector $\boldsymbol\theta$ the posterior predictive is given by the following</p> +<p>$$ +p(X|D) = \int p(X | \boldsymbol\theta, D) p(\boldsymbol\theta | D)\ d\boldsymbol\theta +$$</p> +<p>Before we can integrate this, let us introduce <a href="https://stats.stackexchange.com/a/166574/109849">a small +trick</a>. For any +$\boldsymbol\theta = (\theta_1,\ldots,\theta_m)$ let us define +$\theta_{\neg j} = (\theta_1, \ldots, \theta_{j-1}, \theta_{j+1}, +\ldots, \theta_m)$, that is all $\theta_i$ except for $\theta_j$. +Using this we can write a marginal $p(\theta_j)$ as</p> +<p>$$ +\int p(\theta_j, \theta_{\neg j})\ d \theta_{\neg j} = p(\theta_j) +$$</p> +<p>The posterior predictive</p> +<p>$$ +p(X = j | \boldsymbol\theta) = \int p(X | \boldsymbol\theta) p(\boldsymbol\theta)\ d\theta +$$</p> +<p>can then be re-written using this trick as a double integral</p> +<p>$$ +\int_{\theta_j} \int_{\theta_{\neg j}} p(X = j | \boldsymbol\theta) +p(\boldsymbol\theta)\ d\theta_{\neg j}\ d\theta_j. +$$</p> +<h3 id="posterior-predictive-for-single-trival-dirichlet-categorical">Posterior predictive for single trival Dirichlet-Categorical</h3> +<p>If we&rsquo;re considering a single-trial multinomial (multinoulli) we have $p(X += j | \boldsymbol\pi) = \pi_j$, which is independent of +$\pi_{\neg j}$, simplifying the above expression</p> +<p>$$ +\int_{\pi_j} \pi_j \int_{\pi_{\neg j}} p(\boldsymbol\pi)<br> +d\pi_{\neg j}\ d\pi_j. +$$</p> +<p>Now applying the marginalization trick we get $\int_{\pi_{\neg j}} +p(\pi)\ d\pi_{\neg j} = p(\pi_j)$ and our posterior has the +form</p> +<p>$$ +\int_{\pi_j} \pi_j p(\pi_j)\ d\pi_j. +$$</p> +<p>Looking more closely at the formula, we can see this is an expectation of +$\pi_j$ under the posterior, that is</p> +<p>$$ +\int_{\pi_j} \pi_j p(\pi_j | D)\ d\pi_j = E[\pi_j | +D] = \frac{\alpha_j + x_j}{\sum_{i=1}^m \left( \alpha_i + x_i +\right)} = \frac{\alpha_j + x_j}{\alpha_0 + N} +$$</p> +<p>where $\alpha_0 = \sum_{i=1}^m \alpha_i$ and $N = \sum_{i=1}^m x_i$. +Repeating the result one more time for clarity, the posterior predictive +for a single trial Multinomial (Multinoulli) is given by</p> +<p>$$ +p(X=j | D) = \frac{\alpha_j + x_j}{\alpha_0 + N} +$$</p> +<h3 id="posterior-predictive-for-a-general-multi-trial-dirichlet-multinomial">Posterior predictive for a general multi-trial Dirichlet-Multinomial</h3> +<p>Generalizing the posterior predictive to a Dirichlet-Multinomial model with +multiple trials is going to be a little bit more work. Let us begin by writing +the posterior predictive in its full form (note we drop the conditioning on $D$ +in the likelihood for brevity, and because it is not needed). To avoid notation +clashes, let us replace the posterior $\boldsymbol\alpha + \boldsymbol x$ by +$\boldsymbol \alpha&rsquo;$, so we&rsquo;ll write $Dir(\boldsymbol\alpha&rsquo;)$ and $\alpha_i&rsquo;$ +in place of $Dir(\boldsymbol\alpha + \boldsymbol x)$ and $\alpha_i + x_i$.</p> +<p>$$ +\begin{align} +p(X|D) &amp;= \int p(X | \boldsymbol\pi) p(\boldsymbol\pi | D)\ d\boldsymbol\pi \\\\ +&amp;= \int Mult(X | \boldsymbol\pi) Dir(\boldsymbol\alpha&rsquo;) \ d\boldsymbol\pi \\\\ +&amp;= \int \left(\binom{n!}{x_1! \ldots x_m!} \prod_{i=1}^m \pi_i^{x_i} \right) +\left(\frac{1}{B(\boldsymbol\alpha + \boldsymbol x)} \prod_{i=1}^m \pi_i^{\alpha_i&rsquo; - 1} \right) \ d\boldsymbol\pi \\\\ +&amp;= \binom{n!}{x_1! \ldots x_m!} \frac{1}{B(\boldsymbol\alpha&rsquo;)} +\int \prod_{i=1}^m \pi_i^{x_i} \prod_{i=1}^m \pi_i^{\alpha_i&rsquo; - 1} \ d\boldsymbol\pi \\\\ +&amp;= \binom{n!}{x_1! \ldots x_m!} \frac{1}{B(\boldsymbol\alpha&rsquo;)} +\int \prod_{i=1}^m \pi_i^{x_i + \alpha_i&rsquo; - 1} \ d\boldsymbol\pi \\\\ +&amp;= \binom{n!}{x_1! \ldots x_m!} \frac{1}{B(\boldsymbol\alpha&rsquo;)} B(\boldsymbol\alpha&rsquo; + \boldsymbol x) \\\\ +\end{align} +$$</p> +<p>where in the last equality we made use of knowing that the integral of an +unnormalized Dirichlet distribution is $B(\boldsymbol\alpha)$. Let us repeat +the definition of $B(\boldsymbol\alpha)$ again, that is</p> +<p>$$ +B(\boldsymbol\alpha) = \frac{\prod_{i=1}^m \Gamma(\alpha_i)}{\Gamma(\sum_{i=1}^m \alpha_i)} +$$</p> +<p>and plugging this back into the formula we computed</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<p>$$ +\begin{align} +p(X|D) &amp;= \binom{n!}{x_1! \ldots x_m!} \frac{1}{B(\boldsymbol\alpha&rsquo;)} B(\boldsymbol\alpha&rsquo; + \boldsymbol x)\\\\ +&amp;= \frac{n!}{x_1! \ldots x_m!} \frac{\Gamma(\sum_{i=1}^m \alpha_i&rsquo;)}{\prod_{i=1}^m \Gamma(\alpha_i&rsquo;)} +\frac{\prod_{i=1}^m \Gamma(\alpha_i&rsquo; + x_i)}{\Gamma(\sum_{i=1}^m \alpha_i&rsquo; + x_i)} \\\\ +\end{align} +$$</p> +<p>To move forward, we need to introduce a more general form for the multinomial distribution +which allows for non-integer counts. All it comes down is basically replacing factorials with +the gamma function, that is instead of</p> +<p>$$ +p(\boldsymbol x | \boldsymbol\pi, n) = \binom{n!}{x_1!\ldots x_m!} \prod_{i=1}^m \pi_i^{x_i} +$$</p> +<p>we write</p> +<p>$$ +p(\boldsymbol x | \boldsymbol\pi, n) = \frac{\Gamma(\sum_{i=1}^m x_i + +1)}{\prod_{i=1}^m \Gamma(x_i + 1)} \prod_{i=1}^m \pi_i^{x_i}. +$$</p> +<p>Since only the normalizing constant changed, we can plug it back into our posterior predictive formula</p> +<p>$$ +\begin{align} +p(X|D) &amp;= \frac{\Gamma(\sum_{i=1}^m x_i + 1)}{\prod_{i=1}^m \Gamma(x_i + 1)} +\frac{\Gamma(\sum_{i=1}^m \alpha_i&rsquo;)}{\prod_{i=1}^m \Gamma(\alpha_i&rsquo;)} +\frac{\prod_{i=1}^m \Gamma(\alpha_i&rsquo; + x_i)}{\Gamma(\sum_{i=1}^m \alpha_i&rsquo; + x_i)} \\\\ +\end{align} +$$</p> +<p>which although ugly, it is the posterior predictive distribution in closed form :)</p> +<h3 id="references">References</h3> +<ul> +<li><a href="https://www.cs.ubc.ca/~murphyk/MLbook/">Machine Learning - A Probabilistic Perspective, chapter 3.4.4, by Kevin P. Murphy</a></li> +<li><a href="https://people.eecs.berkeley.edu/~stephentu/writeups/dirichlet-conjugate-prior.pdf?fbclid=IwAR1pBuknQZiTdDFj2_KDUaD8b5lSSbwlk1NYyZfmhPZ3rExg1lctc_kQCzw">The Dirichlet-Multinomial and Dirichlet-Categorical models for Bayesian inference by Stephen Tu</a></li> +</ul> + + + + + Maximum Likelihood for the Multinomial Distribution (Bag of Words) + https://blog.jakuba.net/maximum-likelihood-for-multinomial-distribution/ + Mon, 03 Dec 2018 23:52:59 +0100 + + https://blog.jakuba.net/maximum-likelihood-for-multinomial-distribution/ + <p>In this short article we&rsquo;ll derive the maximum likelihood estimate (MLE) of the +parameters of a Multinomial distribution. If you need a <a href="https://blog.jakuba.net/dirichlet-categorical-model/">refresher on the +Multinomial distribution, check out the previous article</a>.</p> +<p>Let us begin by repeating the definition of a Multinomial random variable. +Consider the bag of words model where we&rsquo;re counting the nubmer of words in a +document, where the words are generated from a fixed dictionary. The +probability mass function (PMF) is defined as</p> +<p>$$ +p(\boldsymbol x | \boldsymbol \pi, n) = \binom{n!}{x_1! x_2! \ldots x_m!} +\prod_{i=1}^m \pi_i^{x_i} = n! \prod_{i=1}^m \frac{\pi_i^{x_i}}{x_i!} +$$</p> +<p>where $\pi_i$ is the probability of $i-th$ word, $x_i$ is the nubmer of +occurences of that word, $m$ is the number of words in the dictionary, and +$n$ is the total number of occurences of all words.</p> +<p>Since the Multinomial distribution comes from the exponential family, we know +computing the log-likelihood will give us a simpler expression, and since +$\log$ is concave computing the MLE on the log-likelihood will be equivalent +as computing it on the original likelihood function.</p> +<p>Now taking the log-likelihood</p> +<p>$$ +\begin{align} +\log L(\boldsymbol \pi) &amp;= \log n! \left( \prod_{i=1}^m \frac{\pi_i^{x_i}}{x_i!} \right) \\\\ +&amp;= \log n! + \sum_{i=1}^m x_i \log \pi_i - \sum_{i=1}^m \log x_i!. +\end{align} +$$</p> +<p>Before we can differentiate the log-likelihood to find the maximum, we need to introduce +the constraint that all probabilities $\pi_i$ sum up to $1$, that is</p> +<p>$$ +\sum_{i=1}^m \pi_i = 1. +$$</p> +<p>The lagrangian with the constraint than has the following form</p> +<p>$$ +\mathcal{L}(\boldsymbol \pi, \lambda) = \log L(\boldsymbol \pi) + \lambda (1 - \sum_{i=1}^m \pi_i). +$$</p> +<p>To find the maximum, we differentiate the lagrangian w.r.t. $\pi_i$ as follows</p> +<p>$$ +\begin{align} +\frac{\partial}{\partial\pi_i} \mathcal{L}(\boldsymbol\pi, \lambda) &amp;= +\frac{\partial}{\partial\pi_i}\log L(\boldsymbol \pi) + \frac{\partial}{\partial\pi_i} \lambda (1 - \sum_{i=1}^m \pi_i) \\\\ +&amp;= \frac{\partial}{\partial\pi_i}\log L(\boldsymbol \pi) - \lambda \\\\ +&amp;= \frac{\partial}{\partial\pi_i} \left(\log n! + \sum_{i=1}^m x_i \log \pi_i - \sum_{i=1}^m \log x_i! \right) - \lambda \\\\ +&amp;= \frac{x_i}{\pi_i} - \lambda. +\end{align} +$$</p> +<p>Finally, setting the lagrangian equal to zero allows us to compute the extremum as</p> +<p>$$ +\pi_i = \frac{x_i}{\lambda}. +$$</p> +<p>To solve for $\lambda$, we sum both sides and make use of our initial constraint</p> +<p>$$ +\begin{align} +\pi_i &amp;= \frac{x_i}{\lambda} \\\\ +\sum_{i=1}^m \pi_i &amp;= \sum_{i=1}^m \frac{x_i}{\lambda} \\\\ +1 &amp;= \frac{1}{\lambda }\sum_{i=1}^m x_i \\\\ +1 &amp;= \frac{1}{\lambda} n \\\\ +\lambda &amp;= n \\\\ +\end{align} +$$</p> +<p>giving us the final form of the MLE for $\pi_i$, that is</p> +<p>$$ +\pi_i = \frac{x_i}{n} +$$</p> +<p>which is what we would expect. The MLE for a word is exactly its frequency in the document.</p> + + + + + Dirichlet-Categorical Model + https://blog.jakuba.net/dirichlet-categorical-model/ + Sun, 02 Dec 2018 00:06:08 +0100 + + https://blog.jakuba.net/dirichlet-categorical-model/ + <p>In the previous article we looked at the <a href="https://blog.jakuba.net/beta-distribution/">Beta-Bernoulli model</a>. This time we&rsquo;ll extend it to a model with +multiple possible outcomes. We&rsquo;ll also take a look at the Dirichlet, +Categorical and Multinomial distributions.</p> +<p>After this, we&rsquo;ll be quite close to implementing interesting models such as the +Latent Dirichlet Allocation (LDA). But for now, we have to understand the +basics first.</p> +<h3 id="multinomial-coefficients">Multinomial coefficients</h3> +<p>Before we can dive into the dirichlet-categorical model we have to briefly look +at the multinomial coefficient, which is the generalization of a binomial +coefficient. First, here&rsquo;s a definition of the binomial coefficient</p> +<p>$$ +\binom{n}{k} = \frac{n!}{k! (n - k)!} +$$</p> +<p>which represents the number of ways we can choose $k$ items out of $n$ total.</p> +<p>We can generalize this to more than two types of items using the <strong>multinomial +coefficient</strong> defined as</p> +<p>$$ +\binom{n}{k_1, k_2, \ldots, k_m} = \frac{n!}{k_1! k_2! \ldots k_m!}. +$$</p> +<p>which represents the number of ways we can split $n$ items into $m$ groups, +with $k_1$ items in the first group, $k_2$ items in the second group, and so +on.</p> +<h3 id="categorical-distribution">Categorical distribution</h3> +<p>Now that we are comfortable with multinomial coefficients, let us continue with +the generalization of the Bernoulli distribution, that is the Categorical +distribution, denoted as $Cat(\boldsymbol{\pi})$, where $\boldsymbol\pi$ is a +vector of probabilities for each possible outcome. The probability mass +function (PMF) is simply</p> +<p>$$ +p(x|\boldsymbol \pi) = \prod_{i=1}^k \pi_i^{I[x = i]} +$$</p> +<p>where $I[x = i]$ is an indicator variable which evaluates to $1$ if $x=i$, or +to $0$ otherwise. Note that we require $\sum_{i=1}^k \pi_i = 1$.</p> +<p>We can also re-formulate this for the case of one-of-K encoding, where only one +of the outcomes is $1$, and the remaining elements equal $0$. Then the +distribution becomes</p> +<p>$$ +p(x|\boldsymbol\pi) = \prod_{i=1}^k \pi_i^{x_i}. +$$</p> +<p>An example of this would be a single roll of a dice, where only one of the +outcomes is possible, but each might have a different probability (unfair +dice).</p> +<h3 id="multinomial-distribution">Multinomial distribution</h3> +<p>Having understood the Categorical distribution, we can now move to the +generalization of the Binomial distribution to multiple outcomes, that is the +Multinomial distribution. An easy way to think of it is $n$ rolls of a +$k$-sided dice.</p> +<ul> +<li>When $n = 1$ and $k = 2$ we have a Bernoulli distribution.</li> +<li>When $n = 1$ and $k &gt; 2$ we have a Categorical distribution.</li> +<li>When $n &gt; 1$ and $k = 2$ we have a Binomial distribution.</li> +<li>And finally, when $n &gt; 1$ and $k &gt; 2$ we have a Multinomial distribution.</li> +</ul> +<p>Of course we can simply always use the Multinomial distribution as it is the +most general. The PMF in the one-of-K case is then simply</p> +<p>$$ +p(\boldsymbol{x} | \boldsymbol{\pi},n) = \binom{n!}{x_1!x_2! \ldots x_k!} \prod_{i=1}^k \pi_i^{x_i} +$$</p> +<p>In this case $\boldsymbol{x} = (x_1, \ldots, x_k)$ represent the number of +times each outcome was observed, while again $\boldsymbol{\pi} = (\pi_1, +\ldots, \pi_k)$ represent the probabilities of each outcome.</p> +<p>An example of the multinomial distribution is the Bag of Words model, which +describes the number of occurences of each word in a dataset. There are $k$ +possible words in a dictionary and the document consists of $n$ words in total.</p> +<h3 id="dirichlet-distribution">Dirichlet distribution</h3> +<p>Lastly, let us consider the Dirichlet distribution, which is a generalization +of the Beta distribution to more than two outcomes. The Dirichlet distribution +is to the Categorical/Mutlinomial what the Beta is to the Bernoulli/Binomial.</p> +<p>A random vector $\boldsymbol{\pi} = (\pi_1, \ldots, \pi_k)$ with $\sum_{i=1}^k \pi_i = +1$ and $\pi_i \in (0; 1)$ has a Dirichlet distribution with a PMF</p> +<p>$$ +Dir(\boldsymbol{\pi} | \alpha_1, \ldots, \alpha_m) = \frac{\Gamma(\sum_{i=1}^k +\alpha_i)}{\prod_{i=1}^k \Gamma(\alpha_i)} \prod_{i=1}^k \pi_i^{\alpha_i - +1}. +$$</p> +<p>Just like we did with the Beta distribution, we can simplify things by naming +normalization constant, as it can be computed in closed form from the parameters, +that is</p> +<p>$$ +Dir(\boldsymbol{\pi} | \alpha_1, \ldots, \alpha_m) = +\frac{1}{B(\boldsymbol{\alpha})} \prod_{i=1}^k \pi_i^{\alpha_i - 1} +$$</p> +<p>where</p> +<p>$$ +B(\boldsymbol{\alpha}) = \frac{\prod_{i=1}^k \Gamma(\alpha_i)}{\Gamma(\sum_{i=1}^k \alpha_i)}. +$$</p> +<p>Note that for shorthand we will also write $\boldsymbol\alpha = (\alpha_1, +\ldots, \alpha_k)$, giving us a shorter notation when writing +$Dir(\boldsymbol\pi | \boldsymbol\alpha)$.</p> +<h3 id="dirichlet-categorical-model">Dirichlet-Categorical Model</h3> +<p>Similarly in the previous article about the <a href="https://blog.jakuba.net/beta-distribution/">Beta-Bernoulli model</a> we will now introduce the +Dirichlet-Categorical model. Since everything is analogous we won&rsquo;t go into +that much detail. The Dirichlet distribution is a conjugate prior to the +Categorical and Multinomial distributions, which means if we set our prior to +Dirichlet and our likelihood to Categorical or Mutlinomial, the resulting +distribution will again be a Dirichlet distribution.</p> +<p>We can observe this easily by just multiplying out the probability mass +functions for $Cat(\boldsymbol x | \boldsymbol \pi)$ and +$Dir(\boldsymbol\pi|\boldsymbol\alpha)$, that is</p> +<p>$$ +Cat(\boldsymbol x | \boldsymbol \pi) Dir(\boldsymbol\pi|\boldsymbol\alpha) +\propto \prod_{i=1}^k \pi_i^{x_i} \prod_{i=1}^k \pi_i^{\alpha_i - 1}. +$$</p> +<p>Since only one of the $x_i$ in the Categorical distribution can be $1$ and the +rest are $0$, say $x_j =1 $, then this will get multiplied by the respective +$\pi_j$ in the Dirichlet distribution and we can immediately see that +$\alpha_j$ will be increased by one, giving us a new Dirichlet distribution +with a parameter $(\alpha_1, \ldots, \alpha_j + 1, \ldots, \alpha_k)$.</p> + + + + + Beta Distribution and the Beta-Bernoulli Model + https://blog.jakuba.net/beta-distribution/ + Sat, 01 Dec 2018 19:08:14 +0100 + + https://blog.jakuba.net/beta-distribution/ + <p>The Beta distribution is a parametric distribution defined on the interval $[0; +1]$ with two positive shape parameters, denoted $\alpha$ and $\beta$. Probably +the most common use case is using Beta as a distribution over probabilities, as +in the case of the parameter of a Bernoulli random variable. Even more +importantly, the Beta distribution is a conjugate prior for the Bernoulli, +binomial, negative binomial and geometric distributions.</p> +<p>The PDF of the Beta distribution, for $x \in [0; 1]$ is defined as</p> +<p>$$ +p(x | \alpha, \beta) = \frac{1}{B(\alpha, \beta)} x^{\alpha - 1} (1 - x)^{\beta - 1} +$$</p> +<p>where $B(\alpha, \beta)$ is the normalizing constant which can be directly +computed from the parameters using the gamma function (denoted $\Gamma$ and +defined via an integral $\Gamma(z) = \int_0^\infty x^{z-1} e^{-x}\ dx$) as +follows</p> +<p>$$ +B(\alpha, \beta) = \frac{\Gamma(\alpha) \Gamma(\beta)}{\Gamma(\alpha + \beta)}. +$$</p> +<p>This gives us the complete form of the PDF</p> +<p>$$ +Beta(x | \alpha, \beta) = \frac{\Gamma(\alpha + \beta)}{\Gamma(\alpha) +\Gamma(\beta)} x^{\alpha - 1} (1 - x)^{\beta - 1}. +$$</p> +<p>Because of the conjugacy, we rarely have to worry about the normalizing constant +and can simply compute it in closed form.</p> +<p>As a small aside, let us compute the expectation of a Beta random variable $X +\sim Beta(\alpha, \beta)$. Note that the support of the Beta distribution is +$[0; 1]$, which means we&rsquo;re only integrating over that interval.</p> +<p>$$ +\begin{align} +\mu = E[X] &amp;= \int_0^1 x p(x | \alpha, \beta)\ dx \\\\ +&amp;= \int_0^1 x \frac{x^{\alpha - 1} (1 - x)^{\beta - 1}}{B(\alpha, \beta)}\ dx \\\\ +&amp;= \frac{1}{B(\alpha, \beta)}\int_0^1 x^{\alpha} (1 - x)^{\beta - 1}\ dx \\\\ +\end{align} +$$</p> +<p>Here we make use of a simple trick. Since $B(\alpha, \beta)$ is the normalizing +constant, it must hold that the integral over an unnormalized $Beta(\alpha, \beta)$ +distribution is exactly $B(\alpha, \beta)$, that is</p> +<p>$$ +\int_0^1 x^{\alpha - 1} (1 - x)^{\beta - 1}\ dx = B(\alpha, \beta). +$$</p> +<p>If we look at the integral we got in the previous expression, it is very similar, +except the $\alpha$ instead of $\alpha - 1$. But that is ok, it simply corresponds to +$B(\alpha + 1, \beta)$. We can plug this back in and get</p> +<p>$$ +\begin{align} +\mu &amp;= \frac{B(\alpha + 1, \beta)}{B(\alpha, \beta)} \\\\ +&amp;= \frac{\Gamma(\alpha + 1)\Gamma(\beta)}{\Gamma(\alpha + 1 + \beta)} +\frac{\Gamma(\alpha + \beta)}{\Gamma(\alpha)\Gamma(\beta)} \\\\ +&amp;= \frac{\alpha \Gamma(\alpha)\Gamma(\beta)}{(\alpha + \beta)\Gamma(\alpha + +\beta)} \frac{\Gamma(\alpha + \beta)}{\Gamma(\alpha)\Gamma(\beta)} \\\\ +&amp;= \frac{\alpha}{\alpha + \beta} \\\\ +\end{align} +$$</p> +<p>using the identity $\Gamma(x + 1) = x \Gamma(x)$.</p> +<h2 id="beta-bernoulli-model">Beta-Bernoulli model</h2> +<p>Let us now show a simple example where we make use of the conjugacy between +Beta and Bernoulli distributions.</p> +<p>Consider a random variable representing the outcome of a single coin toss, +which has a Bernoulli distribution with a parameter $\theta$ (probability of heads). +Before we observe the coin toss, we might have some prior belief about the +fairness of the coin. Let us set the prior belief as if we&rsquo;ve seen 1 head and 1 +tail before tossing the coin, that is $Beta(1, 1)$.</p> +<p>Because Bayesian inference models uncertainty directly, this does not mean that +we believe the coin is fair, even though the maximum likelihood estimate of +$\theta$ for these two coin tosses would be $0.5$. We are however interested in +computing the full posterior over $\theta$, that is $p(\theta | D)$ where $D$ +is our observed data. Using Bayes theorem we get</p> +<p>$$ +p(\theta | D) = \frac{p(\theta | \alpha, \beta) p(D | \theta)}{p(D)}. +$$</p> +<p>Now knowing that the Beta distribution is a conjugate prior for the Bernoulli +distribution, and given that our prior is Beta and our likelihood is Bernoulli, +we know that our posterior must be a Beta distribution as well. We can thus +omit the normalizing constant $p(D)$ since we can infer it from the computed +parameters from multiplying the prior by the likelihood.</p> +<p>Let&rsquo;s say we toss the coin once and observe heads. We can write the likelihood</p> +<p>$$ +p(D | \theta) = \theta +$$</p> +<p>and putting this together with the prior</p> +<p>$$ +p(\theta | \alpha, \beta) \propto \theta^{\alpha - 1} (1 - \theta)^{\beta - 1} +$$</p> +<p>we can compute the posterior</p> +<p>$$ +p(\theta | D) \propto \theta\theta^{\alpha - 1} (1 - \theta)^{\beta - 1} = \theta^{(\alpha - 1) + 1} (1 - \theta)^{\beta - 1} \propto Beta(\theta | \alpha + 1, \beta). +$$</p> +<p>As you can see, multiplying the likelihood and the prior gives again gives a +distribution which is exactly the same shape as a Beta distribution. We can thus +infer back the normalizing constant to be $B(\alpha + 1, \beta)$ and write our full +posterior in closed form</p> +<p>$$ +p(\theta | D) = \frac{1}{B(\alpha + 1, \beta)} \theta^{\alpha} (1 - \theta)^{\beta - 1} +$$</p> +<p>If we observed tails, the likelihood would be $p(D | \theta) = 1 - \theta$ +since $\theta$ is the probability of heads. Plugging this back into the +previous formula we can easily see that the resulting distribution would be +$Beta(\alpha, \beta + 1)$.</p> +<p>The Beta distribution basically acts as a <em>counter</em>. With every newly observed +coin toss it gets added to our existing prior belief to compute the posterior, +which then can become a prior for the next coin toss, but with our belief updated. +This is a simple example of how Bayesian models can be updated on-line as new data +comes in.</p> + + + + + The Gaussian Distribution - Basic Properties + https://blog.jakuba.net/the-gaussian-distribution---basic-properties/ + Sat, 01 Dec 2018 02:59:25 +0100 + + https://blog.jakuba.net/the-gaussian-distribution---basic-properties/ + <p>The Gaussian distribution has many interesting properties, many of which make +it useful in various different applications. Before moving further, let us just +define the univariate PDF with a mean $\mu$ and variance $\sigma^2$</p> +<p>$$ +\mathcal{N}(x | \mu, \sigma^2) = \frac{1}{\sqrt{2 \pi \sigma^2}} \exp \left( -\frac{(x - \mu)^2}{2 \sigma^2} \right). +$$</p> +<p>In the general multi-dimensional case, the mean becomes a mean vector, and the variance turns into +a $D \times D$ covariance matrix. The PDF then becomes</p> +<p>$$ +\mathcal{N}(\mathbf{x} | \mathbf{\mu}, \mathbf{\Sigma}) = \frac{1}{\sqrt{(2 \pi)^k det(\mathbf{\Sigma})}} +\exp \left( -\frac{1}{2} (\mathbf{x} - \mathbf{\mu})^T \mathbf{\Sigma}^{-1} (\mathbf{x} - \mathbf{\mu}) \right) +$$</p> +<p>where $det(\Sigma)$ is the determinant of the covariance matrix $\Sigma$. The +term in the exponent is called <em>Mahalanobis distance</em> and is useful to study in +more detail.</p> +<h2 id="affine-property">Affine property</h2> +<p>The first property of the Gaussian states that if $X \sim \mathcal{N}(\mu, +\Sigma)$, then $Y = A X + b$ is also a Gaussian, specifically $Y \sim +\mathcal{N}(A \mu + b, A \Sigma A^T)$. We can prove this using the definition of +mean and covariance. The mean of $Y$ (denoted $\mu_Y$) can be derived simply +from the linearity of expectation, that is</p> +<p>$$ +\mu_Y = E[Y] = E[A X + b] = E[A X] + E[b] = A E[X] + b = A \mu + b. +$$</p> +<p>And now the covariance $\Sigma_Y$ we again substitute into the definition +of covariance and get</p> +<p>$$ +\begin{align} +\Sigma_Y &amp;= E[(Y - \mu_Y) (Y - \mu_Y)^T] \\\\ +&amp;= E[((A X + b) - (A \mu + b)) ((A X + b) - (A \mu + b))^T] \\\\ +&amp;= E[(A(X - \mu)) (A (X - \mu))^T] \\\\ +&amp;= E[A (X - \mu) (X - \mu)^T A^T] \\\\ +&amp;= A E[(X - \mu) (X - \mu)^T] A^T \\\\ +&amp;= A \Sigma A^T +\end{align} +$$</p> +<p>and thus $\Sigma_Y = A \Sigma A^T$, which gives the final result of</p> +<p>$$ +Y \sim \mathcal{N}(A \mu, A \Sigma A^T). +$$</p> +<h2 id="sampling-from-a-gaussian">Sampling from a Gaussian</h2> +<p>We can immediately make use of the affine property to define how to sample from +a multivariate Gaussian. We&rsquo;ll make use of <em>Cholesky decomposition</em>, which for +a positive-definite matrix $\Sigma$ returns a lower triangular matrix $L$, such +that</p> +<p>$$ +L L^T = \Sigma. +$$</p> +<p>This together with the affine property defined above gives us</p> +<p>$$ +\mathcal{N}(\mu, \Sigma) = \mu + L \mathcal{N}(0, I). +$$</p> +<p>Sampling from the former is thus equivalent to sampling from the latter. Since +$\mu$ and $L$ are constant factors with respect to sampling, we simply have to +figure out how to draw samples from $\mathcal{N}(0, I)$ and then do the affine +transform back to our original distribution.</p> +<p>Observe that since the covariance of $\mathcal{N}(0, I)$ is diagonal, the individual +values in the random vector are independent. Note that this <a href="https://en.wikipedia.org/wiki/Normally_distributed_and_uncorrelated_does_not_imply_independent">property is special to the +Gaussian and is a little bit tricky</a>, +but holds in our case, because in this case we&rsquo;re inferring that individual random variables +which are jointly Gaussian but uncorrelated are independent.</p> +<p>Finally, because the variables are independent, we can sample them independently, +which can be done easily using the <a href="https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform">Box-Muller transform</a>. +Once we obtain our $D$ independent samples, we simply multiply by $L$ and add $\mu$ +to obtain correlated samples from our original distribution.</p> +<h3 id="sum-of-two-independent-gaussians-is-a-gaussian">Sum of two independent Gaussians is a Gaussian</h3> +<p>If $X$ and $Y$ random variables with a Gaussian distributions, where $X \sim +\mathcal{N}(\mu_X, \sigma_X^2)$ and $X \sim \mathcal{N}(\mu_X, +\sigma_X^2)$, then</p> +<p>$$ +X + Y \sim \mathcal{N}(\mu_X + \mu_Y, \sigma_X^2 + \sigma_Y^2). +$$</p> +<p>This can be proven many different ways, the simplest of which is probably using +moment generating functions. With the moment generating function of a Gaussian +being</p> +<p>$$ +M_X(t) = \exp \left( t\mu + \frac{1}{2} \sigma^2 t^2 \right), +$$</p> +<p>and using the property of moment generating functions which says how to combine +two independent variables $X$ and $Y$, specifically</p> +<p>$$ +M_{X + Y}(t) = M_X(t) M_Y(t), +$$</p> +<p>we can simply plug in our moment generating function for the Gaussian and get +our result</p> +<p>$$ +\begin{align} +M_{X + Y}(t) &amp;= M_X(t) M_Y(t) \\\\ +&amp;= \exp \left( t\mu_X + \frac{1}{2} \sigma_X^2 t^2 \right) \exp \left( t\mu_Y + \frac{1}{2} \sigma_Y^2 t^2 \right) \\\\ +&amp;= \exp \left( t(\mu_X + \mu_Y) + \frac{1}{2} t^2 (\sigma_X^2 + \sigma_Y^2) \right) +\end{align} +$$</p> +<h3 id="deriving-the-normalizing-constant">Deriving the normalizing constant</h3> +<p>We can compute the Gaussian integral using polar coordinates. Consider the zero mean unit variance case.</p> +<p>$$ +\begin{align} +\left( \int_{-\infty}^\infty e^{-x^2} dx \right)^2 &amp;= +\int_{-\infty}^\infty e^{-x^2} dx \int_{-\infty}^\infty e^{-x^2} dx \\\\ +&amp;= \int_{-\infty}^\infty e^{-x^2} dx \int_{-\infty}^\infty e^{-y^2} dy \qquad \text{rename $x$ to $y$}\\\\ +&amp;= \int_{-\infty}^\infty \int_{-\infty}^\infty e^{-(x^2 + y^2)} dx\ dy +\end{align} +$$</p> +<p>And now comes an important trick, we&rsquo;ll do a polar coordinate substitution, +since $e^{-(x^2 + y^2)} = e^{-r^2}$ in $R^2$.</p> +<p>$$ +\begin{align} +&amp;= \int_{-\infty}^\infty \int_{-\infty}^\infty e^{-(x^2 + y^2)} dx\ dy\\\\ +&amp;= \int_0^{2\pi} \int_0^\infty e^{-r^2} r\ dr\ d\theta \\\\ +&amp;= 2\pi \int_0^\infty e^{-r^2} r\ dr \\\\ +\end{align} +$$</p> +<p>now substituting $s = -r^2$ and $ds = -2 r\ dr$, giving us</p> +<p>$$ +\begin{align} +&amp;= 2\pi \int_0^\infty e^{-r^2} r\ dr \\\\ +&amp;= 2\pi \int_0^\infty -\frac{1}{2} e^s\ ds \\\\ +&amp;= \pi \int_0^\infty -e^s\ ds \qquad\text{flipping integration bounds} \\\\ +&amp;= \pi \int_{-\infty}^0 e^s\ ds \\\\ +&amp;= \pi (e^0 - e^{-\infty}) \\\\ +&amp;= \pi +\end{align} +$$</p> +<p>Finally, combining this with the initial integral we get</p> +<p>$$ +\left( \int_{-\infty}^\infty e^{-x^2} dx \right)^2 = \pi +$$</p> +<p>and as a result</p> +<p>$$ +\int_{-\infty}^\infty e^{-x^2} dx = \sqrt{\pi}. +$$</p> +<h3 id="deriving-the-mean-and-standard-deviation">Deriving the mean and standard deviation</h3> +<p>Lastly, while not necessarily a property of the Gaussian, it is a useful +exercise to derive the mean and standard deviation from the PDF. Once again, +the PDF is</p> +<p>$$ +p(x | \mu, \sigma^2) = \frac{1}{\sqrt{2 \pi \sigma^2}} \exp \left( -\frac{(x - \mu)^2}{2 \sigma^2} \right) +$$</p> +<p>and the general formula for $E[X]$ is</p> +<p>$$ +E[X] = \int_{-\infty}^\infty x p(x)\ dx = \int_{-\infty}^\infty x \frac{1}{\sqrt{2 \pi \sigma^2}} \exp \left( -\frac{(x - \mu)^2}{2 \sigma^2} \right)\ dx. +$$</p> +<p>We can pull out the constant outside of the integral and substitute $u = x - +\mu$ and $du = dx$, giving us</p> +<p>$$ +\begin{align} +&amp;= \frac{1}{\sqrt{2 \pi \sigma^2}} \int_{-\infty}^\infty (u + \mu) \exp \left( -\frac{u^2}{2 \sigma^2} \right)\ du \\\\ +&amp;= \frac{1}{\sqrt{2 \pi \sigma^2}} \left( \left( \int_{-\infty}^\infty u \exp \left( -\frac{u^2}{2 \sigma^2} \right)\ du \right) + +\mu \left( \int_{-\infty}^\infty \exp \left( -\frac{u^2}{2 \sigma^2} \right)\ du \right) \right) \\\\ +&amp;= \frac{1}{\sqrt{2 \pi \sigma^2}} \left( \int_{-\infty}^\infty u \exp \left( -\frac{u^2}{2 \sigma^2} \right)\ du \right) + \mu \\\\ +\end{align} +$$</p> +<p>Here we note that the function being integrated is odd, which means the +integral adds up to $0$, and we&rsquo;re left with only $\mu$, that is</p> +<p>$$ +E[X] = \mu +$$</p> +<p>which is what we wanted to prove.</p> +<p>Now for the variance, which is defined as</p> +<p>$$ +var(X) = E[(X - \mu)^2] +$$</p> +<p>which written again as an integral gives us</p> +<p>$$ +var(X) = \int_{-\infty}^\infty (x - \mu)^2 p(x)\ dx = \int_{-\infty}^\infty (x - \mu)^2 \frac{1}{\sqrt{2 \pi \sigma^2}} \exp \left( -\frac{(x - \mu)^2}{2 \sigma^2} \right)\ dx. +$$</p> +<p>again pulling out the constant and substituting $u = x - \mu$ and $du = dx$ we get</p> +<p>$$ +\begin{align} +var(X) &amp;= \frac{1}{\sqrt{2 \pi \sigma^2}} \int_{-\infty}^\infty u^2 \exp \left( -\frac{u^2}{2 \sigma^2} \right)\ du. +\end{align} +$$</p> +<p>Integrating by parts using the $\int u\ v&rsquo; = u\ v - \int v\ u&rsquo;$ where we set</p> +<p>$$ +\begin{align} +u &amp;= y \\\\ +u&rsquo; &amp;= 1 \\\\ +v&rsquo; &amp;= y \cdot e^{-y^2 / 2\sigma^2}. +\end{align} +$$</p> +<p>To get $v$ we have to compute the integral of $v&rsquo;$, which we can easily do substituting $u = -\frac{y^2}{2\sigma^2}$ +and $du = -\frac{y}{\sigma^2} dy$, giving us</p> +<p>$$ +\begin{align} +\int y \cdot e^{-y^2 / 2\sigma^2}\ dy &amp;= -\int \sigma^2 e^u\ du \\\\ +&amp;= -\sigma^2 e^u \\\\ +&amp;= -\sigma^2 e^{-\frac{y^2}{2\sigma^2}}. +\end{align} +$$</p> +<p>Now finishing our integration by parts we can write out the final formula</p> +<p>$$ +\begin{align} +\int u v&rsquo; &amp;= u\ v - \int v\ u&rsquo; \\\\\ +&amp;= \frac{1}{2 \pi \sigma^2} \left( \left[y (-\sigma^2) e^{-\frac{y^2}{2\sigma^2}}\right]_{-\infty}^\infty - \int_{-\infty}^\infty (-s^2) e^{-\frac{y^2}{2s^2}} \ dy \right) \\\\ +&amp;= 0 + \sigma^2 \cdot 1 = \sigma^2. +\end{align} +$$</p> +<p>That is, $var(X) = \sigma^2$.</p> + + + + + Graphical Models: D-Separation + https://blog.jakuba.net/graphical-models---d-separation/ + Thu, 29 Nov 2018 20:51:24 +0100 + + https://blog.jakuba.net/graphical-models---d-separation/ + <p>$$ +\newcommand{\bigci}{\perp\mkern-10mu\perp} +$$</p> +<p>This article is a brief overview of conditional independence in graphical models, and the related d-separation. Let us begin with a definition.</p> +<p>For three random variables $X$, $Y$ and $Z$, we say $X$ is conditionally independent of $Y$ given $Z$ iff</p> +<p>$$ +p(X, Y | Z) = p(X | Z) p(Y | Z). +$$</p> +<p>We can use a shorthand notation</p> +<p>$$ +X \bigci Y | Z +$$</p> +<p>Before we can define d-separation, let us first show three different types of graphs. Consider the same three variables as before, we&rsquo;ll be interested in conditional independence based on whether we observe $Z$.</p> +<h2 id="tail-tail">Tail-tail</h2> +<p>The first case is called the <em>tail-tail</em>.</p> +<!-- raw HTML omitted --> +<p>We can factor the joint distribution to get</p> +<p>$$ +p(X, Y, Z) = p(X | Z) p(Y | Z) p(Z) +$$</p> +<p>and conditioning on the value of $Z$ we get (using the Bayes&rsquo; theorem)</p> +<p>$$ +p(X, Y | Z) = \frac{p(X, Y, Z)}{p(Z)} = \frac{p(X | Z) p(Y | Z) p(Z)}{p(Z)} = p(X | Z) p(Y | Z). +$$</p> +<p>From this we can immediately see that conditioning on $Z$ in the <em>tail-tail</em> case makes $X$ and $Y$ independent, that is $X \bigci Y | Z$.</p> +<h2 id="head-tail">Head-tail</h2> +<p>The second case is called the <em>head-tail</em> and looks as the following.</p> +<!-- raw HTML omitted --> +<p>We can again write the joint distribution for the graph</p> +<p>$$ +p(X, Y, Z) = p(X) p(Z | X) p(Y | Z) +$$</p> +<p>and again conditioning on $Z$ we get (using rules of conditional probability)</p> +<p>$$ +\begin{align} +p(X, Y | Z) &amp;= \frac{p(X, Y, Z)}{p(Z)} \\\\ +&amp;= \frac{p(X) p(Z | X) p(Y | Z)}{p(Z)} \\\\ +&amp;= \frac{p(X, Z) p(Y | Z)}{p(Z)} \\\\ +&amp;= \frac{p(X | Z) p(Z) p(Y | Z)}{p(Z)} \\\\ +&amp;= p(X | Z) p(Y | Z) +\end{align} +$$</p> +<p>and so again, $X$ and $Y$ are conditionally independent given $Z$, that is $X \bigci Y | Z$.</p> +<h4 id="checking-marginal-independence">Checking marginal independence</h4> +<p>For completeness, we can also check if $X$ and $Y$ are marginally independent, which they shouldn&rsquo;t be, since we just showed they&rsquo;re conditionally independent.</p> +<p>$$ +p(X, Y, Z) = p(X) p(Z | X) p(Y | Z) +$$</p> +<p>which gives us the following when marginalizing over $Z$</p> +<p>$$ +p(X, Y) = \sum_Z p(X, Y, Z) = p(X) \sum_Z p(Z | X) p(Y | Z) = p(X) \sum_Z p(Y, Z | X) = p(X) p(Y | X) +$$</p> +<p>from which we can immediately see it does not factorize into $p(X) p(Y)$ in the general case, and thus $X$ and $Y$ are not marginally independent.</p> +<h2 id="head-head">Head-head</h2> +<p>The last case is called the <em>head-head</em> and is a little bit tricky</p> +<!-- raw HTML omitted --> +<p>We can again write out the joint distribution</p> +<p>$$ +p(X, Y, Z) = p(X) p(Y) p(Z | X, Y), +$$</p> +<p>but this does not immediately help us when we try to condition on $Z$, we would want</p> +<p>$$ +p(X, Y | Z) = \frac{p(X, Y, Z)}{p(Z)} \stackrel{?}{=} p(X|Z) p(Y|Z) +$$</p> +<p>which does not hold in general. For example, consider $X, Y \sim Bernoulli(0.5)$ and $Z = 1$ if $X = Y$, and $0$ otherwise. In this case if we know $Z$ and observe $X$, it immediately tells us the value of $Y$, hence $X$ and $Y$ are not conditionally independent given $Z$.</p> +<p>We can however do a little trick and write the $p(X, Y)$ as a marginalization over $Z$, that is</p> +<p>$$ +p(X, Y) = \sum_Z p(X, Y, Z) = \sum_Z p(X) p(Y) p(Z | X, Y) = p(X) p(Y) +$$</p> +<p>since $\sum_Z p(Z | X, Y) = 1$. As a result, in the head-head case we have marginal independence between $X$ and $Y$, that is $X \bigci Y$.</p> +<h2 id="d-separation">D-separation</h2> +<p>Having shown the three cases, we can finally define d-separation. Let $G$ be a DAG, and let $A, B, C$ be disjoint subsets of vertices.</p> +<p>A path between two vertices is <strong>blocked</strong> if it passes through a vertex $v$, such that either:</p> +<ul> +<li>the edges are head-tail or tail-tail, and $v \in C$, or</li> +<li>the edges are head-head, and $v \not \in C$, and neither are any of its descendants.</li> +</ul> +<p>We say that $A$ and $B$ are <strong>d-separated</strong> by $C$ if all paths from a vertex of $A$ to a vertex of $B$ are blocked w.r.t. $C$. And now comes the important part, <strong>if $A$ and $B$ are d-separated by $C$, then $A \bigci B\ |\ C$</strong>.</p> +<p>Thig might all look very complicated, but this property of directed graphical models is actually extremely useful, and very easy to do quickly after seeing just a few examples.</p> +<h2 id="examples">Examples</h2> +<p>To get a feel for d-separation, let us look at the following example ($B$ is observed).</p> +<!-- raw HTML omitted --> +<p>We can immediately see that $A \bigci D | B$ since this is the <em>head-tail</em> case. We can also see that $A \not{\bigci} E | B$ (not conditionally independent), because while the path through $B$ is blocked, the path through $C$ is not.</p> +<hr> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> + + + + + Variational Inference - Deriving ELBO + https://blog.jakuba.net/variational-inference---deriving-elbo/ + Sat, 24 Nov 2018 21:20:11 +0100 + + https://blog.jakuba.net/variational-inference---deriving-elbo/ + <p>This post describes two approaches for deriving the Expected Lower Bound (ELBO) used in variational inference. Let us begin with a little bit of motivation.</p> +<p>Consider a probabilistic model where we are interested in maximizing the marginal likelihood $p(X)$ for which direct optimization is difficult, but optimizing complete-data likelihood $p(X, Z)$ is significantly easier.</p> +<p>In a bayesian setting, we condition on the data $X$ and compute the posterior distribution $p(Z | X)$ over the latent variables given our observed data. This may however require approximate inference. There are two general approaches, sampling using MCMC, and optimization using variational inference.</p> +<p>The main idea behind variational inference is to consider a family of densities $\mathcal(Q)$ over the latent variables, and use optimization to find $q(Z)$ that approximates our target posterior $p(Z | X)$. We measure this using the Kullback-Leiber divergence, that is</p> +<p>$$ +q^*(Z) = {\arg\min}_{q(Z) \in \mathcal{Q}} KL(q(Z)\ ||\ p(Z | X)). +$$</p> +<p>However, optimizing the KL divergence directly is not tractable, because it requires us to compute the log posterior $p(Z | X)$, specifically</p> +<p>$$ +KL(q(Z)\ ||\ p(Z | X)) = -\mathrm{E}_q \left[\log \frac{p(Z | X)}{q(Z)} \right]. +$$</p> +<p>We can however do a bit of equation shuffling (note we omit the explicit density in the expectation since all of them are taken w.r.t $q$)</p> +<p>$$ +\begin{aligned} +KL(q(Z)\ ||\ p(Z | X)) &amp;= -\mathrm{E} \left[\log \frac{p(Z | X)}{q(Z)} \right] \\\\ +&amp;= \mathrm{E} \left[\log \frac{q(Z)}{p(Z | X)} \right] \\\\ +&amp;= \mathrm{E} \left[\log q(Z) \right] - \mathrm{E} \left[\log p(Z | X) \right] \\\\ +&amp;= \mathrm{E} \left[\log q(Z) \right] - \mathrm{E} \left[\log p(Z, X) \right] + \mathrm{E} \left[ \log p(X) \right] \\\\ +&amp;= \mathrm{E} \left[\log \frac{q(Z)}{p(Z, X)} \right] + \log p(X) \\\\ +&amp;= -\mathrm{E} \left[\log \frac{p(Z, X)}{q(Z)} \right] + \log p(X) \\\\ +\end{aligned} +$$</p> +<p>where the last equations is a consequence of $\log p(X)$ being independent of $q(Z)$. Re-writing the equation and moving everything except for $\log p(X)$ to the right we get</p> +<p>$$ +\log p(X) = \mathrm{E} \left[\log \frac{p(Z, X)}{q(Z)} \right] + KL(q(Z)\ ||\ p(Z | X)). +$$</p> +<p>The first term on the right is usually called the <strong>expected lower bound</strong> (ELBO, or <strong>variational lower bound</strong>). Let us denote it as</p> +<p>$$ +\mathcal{L}(q) = \mathrm{E} \left[\log \frac{p(Z, X)}{q(Z)} \right] +$$</p> +<p>giving us the final equation</p> +<p>$$ +\log p(X) = \mathcal{L}(g) + KL(q(Z)\ ||\ p(Z | X)). +$$</p> +<p>Now comes the interesting part. Because we are interested in optimizing by changing $q$, the $\log p(X)$ does not change when $q$ changes. And because the KL divergence between $q(Z)$ and $p(Z | X)$ is always positive, then $\mathcal{L}(g)$ must be a lower bound on $\log p(X)$. As a result, because changing the ELBO by manipulating $q$ does not change $\log p(X)$, the expression on the right must be equal to a constant, which means that increasing $\mathcal{L}(g)$ must decrease $KL(q(Z) || p(Z|X))$. But this is what we wanted all along!</p> +<p>If we find a way to maximize the ELBO, we are effectively minimizing the KL divergence between our approximate distribution $q(Z)$, and our target posterior distribution $p(Z | X)$. If we were to choose $q(Z) = p(Z | X)$, the KL divergence would be zero, and $\mathcal{L}(g) = \log p(X)$. This justifies maximizing the ELBO as an objective in variational inference.</p> +<h2 id="elbo-using-jensens-inequality">ELBO using Jensen&rsquo;s inequality</h2> +<p>The Jensen&rsquo;s inequality will give us a bit of motivation behind the ELBO.</p> +<p>In simple terms, Jensen&rsquo;s inequality states that for a convex function $f(x)$ and a random variable $X$ we get</p> +<p>$$ +E[g(X)] \geq g(E[X]). +$$</p> +<p>Recall that we&rsquo;re interested in</p> +<p>$$ +\log p(X) = \log \left( \sum_Z p(X, Z) \right). +$$</p> +<p>Introducing a new density $q(Z)$ on the latent variable $Z$ we can re-write the last equation as</p> +<p>$$ +\log \left( \sum_Z p(X, Z) \frac{q(Z)}{q(Z)} \right) = \log \left( \sum_Z q(Z) \frac{p(X, Z)}{q(Z)} \right) = \log \mathrm{E}_q \left[ \frac{p(X, Z)}{q(Z)} \right]. +$$</p> +<p>We can now simply apply the Jensen&rsquo;s inequality and immediately arrive at the ELBO as a lower bound, since</p> +<p>$$ +\log p(X) = \log \mathrm{E}_q \left[ \frac{p(X, Z)}{q(Z)} \right] \geq \mathrm{E}_q \left[ \log \frac{p(X, Z)}{q(Z)} \right] = \mathcal{L}(q). +$$</p> +<p>Note that we got the same exact equation as above, showing that $\mathcal{L}$ is indeed a lower bound on $\log p(X)$.</p> +<h3 id="references">References</h3> +<ul> +<li><a href="http://legacydirs.umiacs.umd.edu/~xyang35/files/understanding-variational-lower.pdf">Understanding the Variational Lower Bound, Xitong Yang</a></li> +<li><a href="https://www.cs.ubc.ca/~murphyk/MLbook/">Machine Learning: a Probabilistic Perspective, Kevin Patrick Murphy</a></li> +<li><a href="https://arxiv.org/abs/1601.00670">Variational Inference: A Review for Statisticians, David M. Blei, Alp Kucukelbir, Jon D. McAuliffe</a></li> +<li><a href="https://www.microsoft.com/en-us/research/people/cmbishop/#prml-book">Pattern Recognition and Machine Learning, Christopher Bishop</a></li> +</ul> + + + + + Bellman Equation + https://blog.jakuba.net/bellman-equation/ + Thu, 22 Nov 2018 17:39:21 +0200 + + https://blog.jakuba.net/bellman-equation/ + <p>Before we begin, let me just define a few terms:</p> +<ul> +<li>$S_t$ is the state at time $t$.</li> +<li>$A_t$ is the action performed at time $t$.</li> +<li>$R_t$ is the reward received at time $t$.</li> +<li>$G_t$ is the <strong>return</strong>, that is the sum of discounted rewards received from time $t$ onwards, defined as <code>$G_t = \sum_{i=0}^\infty \gamma^i R_{t+i+1}$</code>.</li> +<li>$V^\pi(s)$ is the value of a state when following a policy $\pi$, that is the expected return when starting in state $s$ and following a policy $\pi$, defined as <code>$V^\pi(s) = E[G_t | S_t = s]$</code>.</li> +<li>$Q^\pi(s, a)$ is the value of a state $s$ when performing and action $a$ and then following the policy $\pi$, that is $Q^\pi(s, a) = E[G_t | S_t = s, A_t = a]$.</li> +</ul> +<p>Before moving further, note a small algebraic tric for re-writing $G_t$ in terms of itself</p> +<!-- raw HTML omitted --> +<p>We can use this in the definition of $V^\pi(s)$ and get</p> +<!-- raw HTML omitted --> +<p>The last equation is called the Bellman equation for $V^\pi(s)$ and it shows a recursive relationship between the value of the current state and the possible next states. This in and of itself is not as interesting, but we&rsquo;ll use it to derive a solution to finding the optimal policy.</p> +<p>Let us now define the optimal value function, that is the value function of the optimal policy (denoted $\pi^*$).</p> +<!-- raw HTML omitted --> +<p>that is the optimal value of a state is the maximum over all possible policies. Going one step further, we also define the optimal action-value function as</p> +<!-- raw HTML omitted --> +<p>It&rsquo;s easy to see now that <code>$V^*(s) = \max_a Q^*(s, a)$</code>, that is the maximum value of a state is computed by performing the best possible action. We can use this further to arrive at a simplified Bellman equation as follows</p> +<!-- raw HTML omitted --> +<p>Here we managed to do a small but important trick in the second last equation (marked with $\stackrel{*}{=}$). But let us first decompose what does $\mathrm{E}_\pi*$ actually mean. Because $G_r$ is the discounted sum of rewards, it is only defined in terms of a policy. But since we assume the policy to be stochastic, we need to take an expectation over all possible actions chosen by the policy, and the possible rewards.</p> +<p>This changes at the marked equation, because we are no longer referring to the policy $\pi_*$, but rather to the value function $V^*$, which is not stochastic. As a reuslt, the expectation in the second to last equation is simply over $R_t$, because we still assume stochastic rewards.</p> +<h3 id="references">References</h3> +<ul> +<li>Equations for the value function and notation borrowed from <a href="https://mitpress.mit.edu/books/reinforcement-learning">Reinforcement Learning: An Introduction by Andrew Barto and Richard S. Sutton</a>.</li> +</ul> + + + + + Linear Regression - least squares with orthogonal projection + https://blog.jakuba.net/linear-regression---least-squares-with-orthogonal-projection/ + Sun, 01 Jul 2018 10:47:11 +0200 + + https://blog.jakuba.net/linear-regression---least-squares-with-orthogonal-projection/ + <p>Compared to the previous article where we simply used vector derivatives we&rsquo;ll now try to derive the formula for least squares simply by the properties of linear transformations and the four fundamental subspaces of linear algebra. These are:</p> +<ul> +<li>Kernel $Ker(A)$: The set of all solutions to $Ax = 0$. Sometimes we can say nullspace $N(A)$ instead of kernel.</li> +<li>Image $Im(A)$: The set of all right sides $b$, for which there is a solution $Ax = b$. We&rsquo;ll show that this is equal to the column space $C(A)$, which is the span of the column vectors in $A$.</li> +<li>Row space $R(A)$: Span of the row vectors in $A$, sometimes also referred to as $Im(A^T)$ (the image of $A^T$). We can also refer to this as $C(A^T)$, because since $Im(A) = C(A)$, then $Im(A^T) = C(A^T) = R(A)$.</li> +<li>Left kernel $Ker(A^T)$ (or left nullspace): The set of all solutions to $A^T x = 0$. The name comes from left multiplying by $x$, specifically the set of solutions to $x^T A = 0^T$.</li> +</ul> +<p>For this derivation we assume that $Ker(A) \perp R(A)$ and $Im(A) \perp Ker(A^T)$.</p> +<p>When <code>A</code> is not invertible (could be rectangular), there is no exact solution to $Ax = b$, because $b$ has a component in $Ker(A^T)$, which is outside the range of $A$ (literally). We can define $b = b_i + b_n$ where $b_i$ is the ortogonal projection of $b$ onto $Im(A)$, and $b_n$ is the ortogonal projection of $b$ onto $Ker(A^T)$. In other words, $b_i \perp b_n$.</p> +<p>The above is valid, because we assume $Im(A) \perp Ker(A^T)$, and that $span(Im(A) \cup Ker(A^T)) = rng(A)$, in other words that $Im(A)$ and $Ker(A^T)$ together generate the whole range of our linear mapping $A$. Now just using basic algebra:</p> +<p>$$ +\begin{align} +b &amp;= b_i + b_n \\\\ +b &amp;= Ax + b_n &amp; \text{left multiply by $A^T$} \\\\ +A^T b &amp;= A^T A x + A^T b_n &amp; \text{since $b_n \in Ker(A^T)$, we know $A^T b_n = 0$} \\\\ +A^T b &amp;= A^T A x &amp; \text{$A^T A$ is invertible, see note below} \\\\ +(A^T A)^{-1} A^T b &amp;= x &amp; \text{finally, we get the normal equation} +\end{align} +$$</p> +<p>Here we used the fact that $A^T A$ is always a symmetric positive semi-definite matrix, and in case we have linearly independent columns, it is actually positive-definite, which means it is also invertible. This is actually easy to show.</p> +<p>First we show that $A^T A$ is symmetric. This is easy to see, because $(A^T A)_{ij}$ is just the dot product of $i$-th row of $A^T$ with the $j-th$ column of $A$. Note that $i$-th row of $A^T$ is actually $i$-th column of $A$. From this we see that $(A^T A)_{ij} = (A^T A)_{ji}$, because dot product is symmetric.</p> +<p>Now we show that $A^T A$ is positive semi-definite. For an arbitrary matrix $M$, we say that $M$ is positive semi-definite if and only if $x^T M x \geq 0$ for all $x \in \mathbb{R}$. We can directly substitute $A^T A$ and use the same trick as below:</p> +<p>$$ +x^T A^T A x = (A x)^T A x = ||A x||^2 \geq 0 +$$</p> +<p>Since $A^T A$ satisfies the definition directly, it is positive-semidefinite. <!-- raw HTML omitted -->$\square$<!-- raw HTML omitted --></p> +<hr> +<p>There is also another very nice way to show that $A^T A$ is invertible, without showing that it is positive semi-definite.</p> +<p><strong>Lemma</strong> $Ker(A^T A) = Ker(A)$.</p> +<p>Starting with $Ker(A^T A) \supseteq Ker(A)$, this follows immediately from $Ax = 0 \implies A^T (Ax) = 0$.</p> +<p>Next $Ker(A^T A) \subseteq Ker(A)$: $A^T A x = 0$, left multiply by $x^T$ and we get:</p> +<p>$$ +0 = x^T A^T A x = (A x)^T A x = || Ax ||^2. +$$</p> +<p>Since the $L_2$ norm is zero only if the vector is zero, we get that any vector $x$ for which $A^T A x = 0$, it is also true that $|| Ax ||^2 = 0$, which can only be true when $A x = 0$, and hence $x \in Ker(A)$. <!-- raw HTML omitted -->$\square$<!-- raw HTML omitted --></p> +<p>Because $Ker(A^T A) = Ker(A)$, we also know that $rank(A^T A) = rank(A)$, which means if $A$ has linearly independent columns, $A^T A$ is invertible, because it has a full rank (this is because $A^T A$ is square and has the same number of rows/columns as $A$ has columns).</p> + + + + + Matrix Inversion Lemma + https://blog.jakuba.net/matrix-inversion-lemma/ + Wed, 16 May 2018 23:12:35 +0200 + + https://blog.jakuba.net/matrix-inversion-lemma/ + <p><strong>This article is a draft and as such there might be typos and other inaccuracies</strong>.</p> +<p>In this article we&rsquo;ll derive the matrix inversion lemma, also known as the Sherman-Morrisson-Woodbury formula. At first it might seem like a very boring piece of linear algebra, but it has a few nifty uses, as we&rsquo;ll see in one of the followup articles.</p> +<p>Let&rsquo;s start with the following block matrix:</p> +<p>$$ +M = \begin{bmatrix} +A &amp; U \\\\ +V &amp; B +\end{bmatrix} +$$</p> +<p>We&rsquo;ll do an <a href="https://en.wikipedia.org/wiki/LU_decomposition#LDU_decomposition">LDU decomposition</a> in two different ways, which basically direclty gives us the end formula. Eliminating the bototm left element we get the following:</p> +<p>$$ +\begin{bmatrix} +I &amp; 0 \\\\ +-V A^{-1} &amp; I +\end{bmatrix} +\begin{bmatrix} +A &amp; U \\\\ +V &amp; B +\end{bmatrix} = \begin{bmatrix} +A &amp; U \\\\ +0 &amp; B - V A^{-1} U +\end{bmatrix}<br> +$$</p> +<p>The <code>$B - V A^{-1} U$</code> is called a <a href="https://en.wikipedia.org/wiki/Schur_complement">Schur complement</a> and is generally defined as follows:</p> +<p>$$ +M/A := V A^{-1} U +$$</p> +<p>We&rsquo;ll use this notation later to make things easier to read. Moving on with the decomposition, we&rsquo;ll now eliminate $U$.</p> +<p>$$ +\begin{bmatrix} +A &amp; U \\\\ +0 &amp; B - V A^{-1} U +\end{bmatrix} \begin{bmatrix} +I &amp; -A^{-1} U \\\\ +0 &amp; I +\end{bmatrix} = \begin{bmatrix} +A &amp; 0 \\\\ +0 &amp; B - V A^{-1} U +\end{bmatrix} +$$</p> +<p>Putting the two equations above together we get the following:</p> +<p>$$ +\underbrace{\begin{bmatrix} +I &amp; 0 \\\\ +-V A^{-1} &amp; I +\end{bmatrix}}_{X} +\underbrace{\begin{bmatrix} +A &amp; U \\\\ +V &amp; B +\end{bmatrix}}_{M} \underbrace{\begin{bmatrix} +I &amp; -A^{-1} U \\\\ +0 &amp; I +\end{bmatrix}}_{Z} = \underbrace{\begin{bmatrix} +A &amp; 0 \\\\ +0 &amp; B - V A^{-1} U +\end{bmatrix}}_{W} +$$</p> +<p>We could also write the matrix $W$ using the Schur complement notation: +$$ +W = \begin{bmatrix} +A &amp; 0 \\\\ +0 &amp; B - V A^{-1} U +\end{bmatrix} = \begin{bmatrix} +A &amp; 0 \\\\ +0 &amp; M/A +\end{bmatrix} +$$</p> +<p>Now we just express $M$ in terms of $X, Z, W$ and take the inverse to get $M^{-1}$.</p> +<p>$$ +\begin{align} +X M Z &amp;= W \\\\ +M Z &amp;= X^{-1} W \\\\ +M &amp;= X^{-1} W Z^{-1} \\\\ +M^{-1} &amp;= (X^{-1} W Z^{-1})^{-1} \\\\ +M^{-1} &amp;= Z W^{-1} X +\end{align} +$$</p> +<p>Substituting our matrices back in, we get:</p> +<p>$$ +\begin{bmatrix} +A &amp; U \\\\ +V &amp; B +\end{bmatrix}^{-1} += \begin{bmatrix} +I &amp; -A^{-1} U \\\\ +0 &amp; I +\end{bmatrix} +\begin{bmatrix} +A^{-1} &amp; 0 \\\\ +0 &amp; (M/A)^{-1} +\end{bmatrix} +\begin{bmatrix} +I &amp; 0 \\\\ +-V A^{-1} &amp; I +\end{bmatrix} +$$</p> +<p>Now comes the fun part, we&rsquo;ll multiply out the right side of the equation:</p> +<p>$$ +\begin{align} +\begin{bmatrix} +A &amp; U \\\\ +V &amp; B +\end{bmatrix}^{-1} +&amp;= \begin{bmatrix} +I &amp; -A^{-1} U \\\\ +0 &amp; I +\end{bmatrix} +\begin{bmatrix} +A^{-1} &amp; 0 \\\\ +0 &amp; (M/A)^{-1} +\end{bmatrix} +\begin{bmatrix} +I &amp; 0 \\\\ +-V A^{-1} &amp; I +\end{bmatrix} \\\\ +&amp;= \begin{bmatrix} +A^{-1} &amp; -A^{-1} U (M/A)^{-1} \\\\ +0 &amp; (M/A)^{-1} +\end{bmatrix} +\begin{bmatrix} +I &amp; 0 \\\\ +-V A^{-1} &amp; I +\end{bmatrix} \\\\ +&amp;= \begin{bmatrix} +A^{-1} + A^{-1} U (M/A)^{-1} V A^{-1} &amp; -A^{-1} U (M/A)^{-1} \\\\ +-(M/A)^{-1} VA^{-1} &amp; (M/A)^{-1} +\end{bmatrix} \\\\ +&amp;= \begin{bmatrix} +A^{-1} + A^{-1} U (B - V A^{-1} U)^{-1} V A^{-1} &amp; -A^{-1} U (B - V A^{-1} U)^{-1} \\\\ +-(B - V A^{-1} U)^{-1} VA^{-1} &amp; (B - V A^{-1} U)^{-1} +\end{bmatrix} +\end{align} +$$</p> +<p>That&rsquo;s it for the first part, now we&rsquo;ll do the same, but eliminating the top-right element from the left first.</p> +<p>$$ +\begin{bmatrix} +I &amp; -U B^{-1} \\\\ +0 &amp; I +\end{bmatrix} \begin{bmatrix} +A &amp; U \\\\ +V &amp; B +\end{bmatrix} = \begin{bmatrix} +A - UB^{-1}V &amp; 0 \\\\ +V &amp; B +\end{bmatrix} +$$</p> +<p>Here we get the other Schur complement, which we&rsquo;ll note as $M/B = A - UB^{-1}V$. We can substitute it in straight away this time.</p> +<p>$$ +\begin{bmatrix} +M/B &amp; 0 \\\\ +V &amp; B +\end{bmatrix} \begin{bmatrix} +I &amp; 0 \\\\ +-B^{-1}V &amp; I +\end{bmatrix} = \begin{bmatrix} +M/B &amp; 0 \\\\ +0 &amp; B +\end{bmatrix} +$$</p> +<p>As before, we&rsquo;ll write it out as a single equation:</p> +<p>$$ +\begin{bmatrix} +I &amp; -U B^{-1} \\\\ +0 &amp; I +\end{bmatrix} +\begin{bmatrix} +A &amp; U \\\\ +V &amp; B +\end{bmatrix} \begin{bmatrix} +I &amp; 0 \\\\ +-B^{-1}V &amp; I +\end{bmatrix} = \begin{bmatrix} +M/B &amp; 0 \\\\ +0 &amp; B +\end{bmatrix} +$$</p> +<p>Now we express the matrix $M$ in terms of the other two (notice the newly added inverse signs):</p> +<p>$$ +\begin{bmatrix} +A &amp; U \\\\ +V &amp; B +\end{bmatrix} = \begin{bmatrix} +I &amp; -U B^{-1} \\\\ +0 &amp; I +\end{bmatrix}^{-1} +\begin{bmatrix} +M/B &amp; 0 \\\\ +0 &amp; B +\end{bmatrix} \begin{bmatrix} +I &amp; 0 \\\\ +-B^{-1}V &amp; I +\end{bmatrix}^{-1} +$$</p> +<p>Lastly, we just take the inverse of both sides:</p> +<p>$$ +\begin{align} +\begin{bmatrix} +A &amp; U \\\\ +V &amp; B +\end{bmatrix}^{-1} &amp;= \left( \begin{bmatrix} +I &amp; -U B^{-1} \\\\ +0 &amp; I +\end{bmatrix}^{-1} +\begin{bmatrix} +M/B &amp; 0 \\\\ +0 &amp; B +\end{bmatrix} \begin{bmatrix} +I &amp; 0 \\\\ +-B^{-1}V &amp; I +\end{bmatrix}^{-1} \right)^{-1} \\\\ +&amp;= \begin{bmatrix} +I &amp; 0 \\\\ +-B^{-1}V &amp; I +\end{bmatrix} +\begin{bmatrix} +M/B &amp; 0 \\\\ +0 &amp; B +\end{bmatrix}^{-1} \begin{bmatrix} +I &amp; -U B^{-1} \\\\ +0 &amp; I +\end{bmatrix} &amp; \text{notice the inverses cancelling out} \\\\ +&amp;= \begin{bmatrix} +I &amp; 0 \\\\ +-B^{-1}V &amp; I +\end{bmatrix} +\begin{bmatrix} +(M/B)^{-1} &amp; 0 \\\\ +0 &amp; B^{-1} +\end{bmatrix} \begin{bmatrix} +I &amp; -U B^{-1} \\\\ +0 &amp; I +\end{bmatrix} \\\\ +&amp;= +\begin{bmatrix} +(M/B)^{-1} &amp; 0 \\\\ +-B^{-1} V (M/B)^{-1} &amp; B^{-1} +\end{bmatrix} \begin{bmatrix} +I &amp; -U B^{-1} \\\\ +0 &amp; I +\end{bmatrix} \\\\ +&amp;= +\begin{bmatrix} +(M/B)^{-1} &amp; -(M/B)^{-1} UB^{-1} \\\\ +-B^{-1} V (M/B)^{-1} &amp; B^{-1} V (M/B)^{-1} UB^{-1} + B^{-1} +\end{bmatrix} \\\\ +&amp;= +\begin{bmatrix} +(A - UB^{-1}V)^{-1} &amp; -(A - UB^{-1}V)^{-1} UB^{-1} \\\\ +-B^{-1} V (A - UB^{-1}V)^{-1} &amp; B^{-1} V (A - UB^{-1}V)^{-1} UB^{-1} + B^{-1} +\end{bmatrix} +\end{align} +$$</p> + + + + + Linear Regression - Least Squares Without Orthogonal Projection + https://blog.jakuba.net/linear-regression---deriving-least-squares-without-orthogonal-projection/ + Tue, 24 Apr 2018 23:28:14 +0200 + + https://blog.jakuba.net/linear-regression---deriving-least-squares-without-orthogonal-projection/ + <p>There are multiple ways one can arrive at the least squares solution to linear regression. I&rsquo;ve always seen the one using orthogonality, but there is another way which I&rsquo;d say is even simpler, especially if you&rsquo;ve done any calculus. Let&rsquo;s define the problem first.</p> +<p>Given a matrix \(N \times M\) matrix \(X\) of inputs, and a vector \(y\) of length \(N\) containing the outputs, the goal is to find a weight vector \(w\) of length \(M\) such that:</p> +<p>$$ +X w \approx y +$$</p> +<p>The reason we&rsquo;re using a \(\approx\) instead of \(=\) is that we&rsquo;re not expecting to fit the line exactly through are training examples, as real world data will contain some form of noise.</p> +<p>To find a best possible fit we&rsquo;ll create a loss function which tells us how well our line fits the data, and then try to minimize the loss. A common choice for regression is the <em>sum of squared errors</em> loss (denoted \(L\)), which is defined as:</p> +<p>$$ +L = \sum_{i = 1}^{N} \left( X_iw - y_i \right)^2 +$$</p> +<p>We can also write this in vector notation using a squared L2 norm</p> +<p>$$ +L = || Xw - y ||^2 +$$</p> +<p>Now here comes the fun part. Because our loss \(L\) is a convex function, it only has a single global minimum, for which we can solve analytically by simply taking a derivative with respect to \(w\) and setting that equal to zero. Before we get into that, let&rsquo;s re-write the loss \(L\) to a form which is more suitable for differentiation:</p> +<p>$$ +\begin{align} +L = || Xw - y ||^2 &amp;= (Xw - y)^T (Xw - y) \\\\ +&amp;= (y^T - w^T X^T) (Xw - y) \\\\ +&amp;= y^T X w - y^T y - w^T X^T X w \\\\ +&amp;= y^T X w + w^T X^T y - y^T y - w^T X^T X w \\\\ +&amp;= y^T X w + (y^T X w)^T - y^T y - w^T X^T X w &amp; \text{transpose of a scalar is a scalar} \\\\ +&amp;= y^T X w + y^T X w - y^T y - w^T X^T X w \\\\ +&amp;= 2 y^T X w - y^T y - w^T X^T X w \\\\ +\end{align} +$$</p> +<p>Before moving any further, let us derive a few vector derivative rules (no pun intended). First, the \(i\)-th row of \(Ax\) is defined as follows:</p> +<p>$$ +\left( Ax \right)_i = \sum_{j=1}^{M} A_{ij} x_j = A_{i1} x_1 + A_{i2} x_2 + \dots + A_{iM} x_M<br> +$$</p> +<p>Now if we take a derivative with respect to \(x_j\) we&rsquo;d get:</p> +<p>$$ +\begin{align} +\frac{\partial}{\partial x_j} \left( Ax \right)_i &amp;= \frac{\partial}{\partial x_j} \left(A_{i1} x_1 + A_{i2} x_2 + \dots + A_{iM} x_M \right) \\\\ +&amp;= \frac{\partial}{\partial x_j} \left(A_{i1} x_1 + A_{i2} x_2 + \dots + A_{ij} x_j + \dots + A_{iM} x_M \right) \\\\ +&amp;= \frac{\partial}{\partial x_j} A_{i1} x_1 + \frac{\partial}{\partial x_j} A_{i2} x_2 + \dots + \frac{\partial}{\partial x_j} A_{ij} x_j + \dots + \frac{\partial}{\partial x_j} A_{iM} x_M \\\\ +&amp;= 0 + 0 + \dots + \frac{\partial}{\partial x_j} A_{ij} x_j + \dots + 0 \\\\ +&amp;= A_{ij} +\end{align} +$$</p> +<p>So this means if we take the \(i\)-th row of the matrix and derive it by the \(j\)-th element in \(x\), we get back \(A_{ij}\). As a result, we get to a nice simple equation:</p> +<p>$$ +\frac{d}{dx} Ax = A +$$</p> +<p>While nice, this doesn&rsquo;t get us very far. We also need to figure out what happens in the case when the vector is on the left as a row vector, as in \(x^T A\)</p> +<p>$$ +(x^T A)_i = \sum_{j = 1}^{M} x_{j}^T A_{ji} +$$</p> +<p>Giving us the following partial derivative:</p> +<p>$$ +\frac{\partial}{\partial x_j} (x^T A)_i = A^T +$$</p> +<p>And finally the interesting part:</p> +<p>$$ +\begin{align} +\frac{\partial x^T A x}{\partial x_i} &amp;= \frac{\partial}{\partial x_i} \left( \sum_{j,k} x_j B_{jk} x_k \right) \\\\ +&amp;= \sum_{j} x_j B_{ji} + \sum_{k} B_{ik} x_k \\\\ +&amp;= \sum_{k} B^T_{ik} x_k + \sum_{k} B_{ik} x_k \\\\ +&amp;= \sum_{k} (B^T_{ik} + B_{ik}) x_k \\\\ +&amp;= \sum_{k} (B^T + B)_{ik} x_k \\\\ +\end{align} +$$</p> +<p>Giving us the final:</p> +<p>$$ +\frac{d}{dx} x^T B x = (B^T + B) x +$$</p> +<p>Which means we can take our loss function and take the derivative with respect to \(w\):</p> +<p>$$ +\begin{align} +\frac{d}{dw} L &amp;= \frac{d}{dw} (2 y^T X w - y^T y - w^T X^T X w) \\\\ +&amp;= 2 y^T X - 0 - w^T ((X^T X)^T + X^T X) &amp; X^T X \ \text{is symmetrical}\\\\ +&amp;= 2 y^T X - w^T (X^T X + X^T X) \\\\ +&amp;= 2 y^T X - 2 w^T X^T X \\\\ +\end{align} +$$</p> +<p>Now we want this to be equal to \(0\) to find the minimum, which gives us the following equation:</p> +<p>$$ +\begin{align} +0 &amp;= 2 y^T X - 2 w^T X^T X \\\\ +2 w^T X^T X &amp;= 2 y^T X \\\\ +w^T &amp;= y^T X (X^T X)^{-1} \\\\ +w &amp;= (X^T X)^{-1} X^T y \\\\ +\end{align} +$$</p> +<p>And there we go, it was a bit of work but we managed to derive the normal equation without the use of orthogonal projection.</p> + + + + + Let's Write a 2D Platformer From Scratch Using HTML5 and JavaScript, Part 3: Collision Detection + https://blog.jakuba.net/2018-02-01-lets-write-a-2d-platformer-from-scratch-part-3/ + Thu, 01 Feb 2018 10:00:00 +0100 + + https://blog.jakuba.net/2018-02-01-lets-write-a-2d-platformer-from-scratch-part-3/ + <p><strong>This article is a part 3 of the <em>Let&rsquo;s Write a 2D Platformer From Scratch Using HTML5 and JavaScript</em> series.</strong></p> +<ul> +<li><a href="https://blog.jakuba.net/2018-01-28-lets-write-a-2d-platformer-from-scratch-part-1/">Part 1: Game Loop</a></li> +<li><a href="https://blog.jakuba.net/2018-01-28-lets-write-a-2d-platformer-from-scratch-part-2/">Part 2: Rendering</a></li> +<li>Part 3: Collision Detection</li> +</ul> +<!-- raw HTML omitted --> +<p>The previous post ended with a very ad-hoc solution to collision detection. We barely managed to get vertical movement working, and didn&rsquo;t even get started on gravity. There&rsquo;s a reason for that. Once the player starts moving vertically, we need something better than just checking against the top left corner we immediately run into issues such as passing through walls below the player, as shown in this image:</p> +<p><img src="https://i.imgur.com/hMMrnmL.png" alt="player stuck in a wall"></p> +<p>What we really want is some concept of a <em>collider</em>, which represents the rigid body of an object. There is however one important distinction. We are only concerning ourselves with collision detection, not full rigid body physics, such as is implemented in <a href="https://github.com/erincatto/Box2D">Box2D</a>. While physics engines provide a huge range of possibilities and features, they are also sometimes difficult to control, <a href="http://jessewarden.com/2012/02/building-an-elevator-in-box2d.html">such as when using elevators</a>, moving platforms, or climbing slopes. What we&rsquo;ll do instead is implement simple horizontal and vertical raycasts which will together with a bit of code provide great control over how the player moves in the world. <a href="https://en.wikipedia.org/wiki/Ray_casting">Ray casting</a> is basically like shooting a laser and seeing where it lands. It will allow us to see which object is the closest in a specific direction, and how far is it.</p> +<p>Some platformers can benefity greatly from the use of a physics engines, such as the popular <a href="http://littlebigplanet.playstation.com/">Little Big Planet</a>. Other platformers, such as <a href="https://en.wikipedia.org/wiki/Super_Mario_Bros.">Super Mario Bros.</a>, which require highly precise controls might be better off being implemented using raycasts, as they give the programmer more control. Physics engines are more inclined to work with things like forces, friction, velocities, etc., while the raycast approach is more in the terms of something like <em>if the player is hugging a wall he can press the jump button</em> where the <em>hugging a wall</em> is determined by doing a raycast on both sides of the player and seeing how far is the closest wall.</p> +<p>To keep things simple we still constrain the game to box-shaped objects instead of arbitrary polygons. Each tile is a square, as is the player. But to make things at least somewhat interesting we&rsquo;ll allow arbitrary shaped boxes, as long as they&rsquo;re not rotated. This is commonly called an <a href="https://en.wikipedia.org/wiki/Minimum_bounding_box#Axis-aligned_minimum_bounding_box">Axis-Aligned Bounding Box</a> (AABB for short).</p> +<p>As a small sidenote, there are already tons of existing libraries for vector math, collision detection, or even specifically ray vs AABB collision detection. I initially didn&rsquo;t intend to do this part completely from scratch and at least use a small vector wrapper like <a href="https://github.com/maxkueng/victor">victor.js</a>, but the library looks basically dead and there are some outstanding issues left unfixed. Then there&rsquo;s <a href="https://github.com/toji/gl-matrix">gl-matrix</a> which seems to be up to date, but seems to be more concerned about performance and WebGL than anything else, which isn&rsquo;t the priority in this series.</p> +<p>Similarly, there is <a href="https://github.com/stackgl/ray-aabb-intersection">ray-aabb-intersection</a> and <a href="https://github.com/tmpvar/ray-aabb">ray-aabb</a> which are both more general than what we&rsquo;ll implement here, but at the same time I feel that one has to ask themselves the question, why are we doing this? If the goal is to write production quality code, we probably wouldn&rsquo;t pick small libraries which haven&rsquo;t had any activity for 2-3 years. If the goal is learning, then we get the most out of it by implementing things ourselves.</p> +<p>I wouldn&rsquo;t be against using a production quality collision library and focus on learning other things, but there doesn&rsquo;t seem to be one available for JavaScript, comparable to something like <a href="http://ncollide.org/">ncollide for Rust</a>, and I don&rsquo;t feel like bringing in the whole of <a href="https://github.com/erincatto/Box2D">Box2D</a> just yet when we&rsquo;re starting out. It will probably come handy in a future blog post when we&rsquo;ll need a more robust solution to collisions and physics.</p> +<h2 id="horizontal-raycast-against-aabbs">Horizontal raycast against AABBs</h2> +<p>Before we move on, let us define a few things:</p> +<ul> +<li><strong>AABB</strong> is a rectangle, which is defined by its top-left corner, width and height.</li> +<li><strong>Ray</strong> is a half-line, which is defined by its origin and direction (up/down/left/right in our case).</li> +<li>A horizontal ray can be in three possible configurations with an AABB (consider ray direction to be <code>right</code>, the <code>left</code> case is symmetrical): +<ul> +<li><strong>Intersection</strong>: the ray starts left of the AABB (<code>ray.origin.x &lt; aabb.x</code>) and hits the AABB (<code>ray.origin.y &gt;= aabb.y &amp;&amp; ray.origin.y &lt;= (aabb.y + aabb.h)</code>).</li> +<li><strong>Inside</strong>: the ray starts in the inner interval of the AABB on the x-axis (<code>ray.origin.x &gt;= aabb.x &amp;&amp; ray.origin.x &lt;= (aabb.x + aabb.w)</code>) and the same for the y-axis (<code>ray.origin.y &gt;= aabb.y &amp;&amp; ray.origin.y &lt;= (aabb.y + aabb.h)</code>).</li> +<li><strong>No intersection</strong>: if neither of the above is true.</li> +</ul> +</li> +</ul> +<blockquote> +<p>When we define these properties, we&rsquo;re thinking in the HTML5 Canvas&rsquo; system of coordinates where positive X means <em>right</em> and positive Y means <em>down</em>. This is different than what the usual Cartesian system of coordinates, which considers its bottom left corner as origin, and positive Y going <em>up</em>.</p> +</blockquote> +<p>Just looking at the definitions, they basically give us the answer already. We could just copy paste the definitions, adjust the comparisons for each of the <code>12</code> cases (<code>3</code> for each direction, and there are <code>4</code> directions) and be done. But let&rsquo;s try to be smart and generalize the conditionals at least a little bit.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> Direction <span style="color:#81a1c1">=</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> UP<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;up&#34;</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> DOWN<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;down&#34;</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> LEFT<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;left&#34;</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> RIGHT<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;right&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">};</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// A ray is defined by its origin and direction. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">function</span> Ray<span style="color:#eceff4">(</span>x<span style="color:#eceff4">,</span> y<span style="color:#eceff4">,</span> dir<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>origin <span style="color:#81a1c1">=</span> <span style="color:#eceff4">{</span> x<span style="color:#81a1c1">:</span> x<span style="color:#eceff4">,</span> y<span style="color:#81a1c1">:</span> y <span style="color:#eceff4">};</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>direction <span style="color:#81a1c1">=</span> dir<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// AABB is defined by its top-left corner, width and height. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">function</span> AABB<span style="color:#eceff4">(</span>x<span style="color:#eceff4">,</span> y<span style="color:#eceff4">,</span> w<span style="color:#eceff4">,</span> h<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>x <span style="color:#81a1c1">=</span> x<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>y <span style="color:#81a1c1">=</span> y<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>w <span style="color:#81a1c1">=</span> w<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>h <span style="color:#81a1c1">=</span> h<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> compareInterval<span style="color:#eceff4">(</span>value<span style="color:#eceff4">,</span> low<span style="color:#eceff4">,</span> high<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// This shouldn&#39;t necessarily be required, but it allows us to just specify +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// the bounds of an interval, without checking which of the two is low and which is high. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>low <span style="color:#81a1c1">&gt;</span> high<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> tmp <span style="color:#81a1c1">=</span> high<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> high <span style="color:#81a1c1">=</span> low<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> low <span style="color:#81a1c1">=</span> tmp<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// And then we simply check if the value lies outside of the interval +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>value <span style="color:#81a1c1">&lt;</span> low<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1">-</span><span style="color:#b48ead">1</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>low <span style="color:#81a1c1">&lt;=</span> value <span style="color:#81a1c1">&amp;&amp;</span> value <span style="color:#81a1c1">&lt;=</span> high<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>value <span style="color:#81a1c1">&gt;</span> high<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> intersect<span style="color:#eceff4">(</span>ray<span style="color:#eceff4">,</span> aabb<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">switch</span> <span style="color:#eceff4">(</span>ray<span style="color:#eceff4">.</span>direction<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">case</span> Direction<span style="color:#eceff4">.</span>UP<span style="color:#81a1c1">:</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">case</span> Direction<span style="color:#eceff4">.</span>DOWN<span style="color:#81a1c1">:</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">case</span> Direction<span style="color:#eceff4">.</span>LEFT<span style="color:#81a1c1">:</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">case</span> Direction<span style="color:#eceff4">.</span>RIGHT<span style="color:#81a1c1">:</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">.</span>x <span style="color:#81a1c1">&lt;=</span> aabb<span style="color:#eceff4">.</span>x<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>compareInterval<span style="color:#eceff4">(</span>ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">.</span>y<span style="color:#eceff4">,</span> aabb<span style="color:#eceff4">.</span>y<span style="color:#eceff4">,</span> aabb<span style="color:#eceff4">.</span>y <span style="color:#81a1c1">+</span> aabb<span style="color:#eceff4">.</span>h<span style="color:#eceff4">)</span> <span style="color:#81a1c1">==</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">{</span> x<span style="color:#81a1c1">:</span> aabb<span style="color:#eceff4">.</span>x<span style="color:#eceff4">,</span> y<span style="color:#81a1c1">:</span> ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">.</span>y <span style="color:#eceff4">};</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1;font-weight:bold">null</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1;font-weight:bold">null</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>Before we move on any further, we should probably test this code to see if it works, since subtle bugs in collision detection could be hard to debug later on when we try to use it in a game. While the spirit of these articles is <em>let&rsquo;s write everything ourselves</em>, I don&rsquo;t feel that writing our own testing framework would be of any benefit, and if you&rsquo;ve read this far, you can probably do it without many issues (at least for the synchronous testing, which is what we&rsquo;ll be doing here).</p> +<p>We&rsquo;ll use <a href="https://qunitjs.com/">QUnit</a>, because it was the only one that literally had a copy-paste-this-and-it-works, which makes it ideal for the JSFiddle based format of these articles. If you have suggestions for a better testing library, please do share them in the comments, but keep in mind that this series is not about setting up the most elaborate build system. If it needs a command line tool to run/build, it&rsquo;s already too much of a hassle.</p> +<p>Here&rsquo;s a few tests for the <code>Direction.RIGHT</code> case:</p> +<!-- raw HTML omitted --> +<p>Implementing the other three directions isn&rsquo;t really challenging as everything is symmetrical. We just have to be careful not to make any mistakes when passing down coordinates. Here&rsquo;s a full <code>intersect</code> function:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> intersect<span style="color:#eceff4">(</span>ray<span style="color:#eceff4">,</span> aabb<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">switch</span> <span style="color:#eceff4">(</span>ray<span style="color:#eceff4">.</span>direction<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">case</span> Direction<span style="color:#eceff4">.</span>UP<span style="color:#81a1c1">:</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">.</span>y <span style="color:#81a1c1">&gt;=</span> aabb<span style="color:#eceff4">.</span>y <span style="color:#81a1c1">+</span> aabb<span style="color:#eceff4">.</span>h<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>compareInterval<span style="color:#eceff4">(</span>ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">.</span>x<span style="color:#eceff4">,</span> aabb<span style="color:#eceff4">.</span>x<span style="color:#eceff4">,</span> aabb<span style="color:#eceff4">.</span>x <span style="color:#81a1c1">+</span> aabb<span style="color:#eceff4">.</span>w<span style="color:#eceff4">)</span> <span style="color:#81a1c1">==</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">{</span> x<span style="color:#81a1c1">:</span> ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">.</span>x<span style="color:#eceff4">,</span> y<span style="color:#81a1c1">:</span> aabb<span style="color:#eceff4">.</span>y <span style="color:#81a1c1">+</span> aabb<span style="color:#eceff4">.</span>h <span style="color:#eceff4">};</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1;font-weight:bold">null</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1;font-weight:bold">null</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">case</span> Direction<span style="color:#eceff4">.</span>DOWN<span style="color:#81a1c1">:</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">.</span>y <span style="color:#81a1c1">&lt;=</span> aabb<span style="color:#eceff4">.</span>y<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>compareInterval<span style="color:#eceff4">(</span>ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">.</span>x<span style="color:#eceff4">,</span> aabb<span style="color:#eceff4">.</span>x<span style="color:#eceff4">,</span> aabb<span style="color:#eceff4">.</span>x <span style="color:#81a1c1">+</span> aabb<span style="color:#eceff4">.</span>w<span style="color:#eceff4">)</span> <span style="color:#81a1c1">==</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">{</span> x<span style="color:#81a1c1">:</span> ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">.</span>x<span style="color:#eceff4">,</span> y<span style="color:#81a1c1">:</span> aabb<span style="color:#eceff4">.</span>y <span style="color:#eceff4">};</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1;font-weight:bold">null</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1;font-weight:bold">null</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">case</span> Direction<span style="color:#eceff4">.</span>LEFT<span style="color:#81a1c1">:</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">.</span>x <span style="color:#81a1c1">&gt;=</span> aabb<span style="color:#eceff4">.</span>x <span style="color:#81a1c1">+</span> aabb<span style="color:#eceff4">.</span>w<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>compareInterval<span style="color:#eceff4">(</span>ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">.</span>y<span style="color:#eceff4">,</span> aabb<span style="color:#eceff4">.</span>y<span style="color:#eceff4">,</span> aabb<span style="color:#eceff4">.</span>y <span style="color:#81a1c1">+</span> aabb<span style="color:#eceff4">.</span>h<span style="color:#eceff4">)</span> <span style="color:#81a1c1">==</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">{</span> x<span style="color:#81a1c1">:</span> aabb<span style="color:#eceff4">.</span>x <span style="color:#81a1c1">+</span> aabb<span style="color:#eceff4">.</span>w<span style="color:#eceff4">,</span> y<span style="color:#81a1c1">:</span> ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">.</span>y <span style="color:#eceff4">};</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1;font-weight:bold">null</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1;font-weight:bold">null</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">case</span> Direction<span style="color:#eceff4">.</span>RIGHT<span style="color:#81a1c1">:</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">.</span>x <span style="color:#81a1c1">&lt;=</span> aabb<span style="color:#eceff4">.</span>x<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>compareInterval<span style="color:#eceff4">(</span>ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">.</span>y<span style="color:#eceff4">,</span> aabb<span style="color:#eceff4">.</span>y<span style="color:#eceff4">,</span> aabb<span style="color:#eceff4">.</span>y <span style="color:#81a1c1">+</span> aabb<span style="color:#eceff4">.</span>h<span style="color:#eceff4">)</span> <span style="color:#81a1c1">==</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">{</span> x<span style="color:#81a1c1">:</span> aabb<span style="color:#eceff4">.</span>x<span style="color:#eceff4">,</span> y<span style="color:#81a1c1">:</span> ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">.</span>y <span style="color:#eceff4">};</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1;font-weight:bold">null</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1;font-weight:bold">null</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>And here&rsquo;s a JSFiddle with test cases for all four of the directions:</p> +<!-- raw HTML omitted --> +<p>We can also create a simple wrapper to calculate the distance of an AABB:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> distance<span style="color:#eceff4">(</span>a<span style="color:#eceff4">,</span> b<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>sqrt<span style="color:#eceff4">(</span><span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>pow<span style="color:#eceff4">(</span>a<span style="color:#eceff4">.</span>x <span style="color:#81a1c1">-</span> b<span style="color:#eceff4">.</span>x<span style="color:#eceff4">,</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">+</span> <span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>pow<span style="color:#eceff4">(</span>a<span style="color:#eceff4">.</span>y <span style="color:#81a1c1">-</span> b<span style="color:#eceff4">.</span>y<span style="color:#eceff4">,</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> raycastDistance<span style="color:#eceff4">(</span>ray<span style="color:#eceff4">,</span> aabb<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> point <span style="color:#81a1c1">=</span> intersect<span style="color:#eceff4">(</span>ray<span style="color:#eceff4">,</span> aabb<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>point<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> distance<span style="color:#eceff4">(</span>ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">,</span> point<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1;font-weight:bold">null</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><h2 id="raycasts-against-multiple-box-colliders">Raycasts against multiple box colliders</h2> +<p>So far we implemented an <code>intersect</code> function which takes a ray and an AABB and calculates the intersection point if there is one. While this is useful, it would be far more useful to have a function which simply takes a ray and returns the closest box collider (AABB) the ray hits if there is one. There are numerous ways we could do this. In the ideal case, we&rsquo;d use a spatial data structure (such as a quad tree or a spatial hash) to figure out the areas through which the ray is cast, and then check against colliders within that area. This avoid iterating the whole world on each raycast. Adding a more intelligent selection of colliders can be done separate from the rest of the code we&rsquo;ll write here which is why we&rsquo;ll simply iterate all of the colliders and return the intersection with the closest one.</p> +<p>The code would look something like this:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> raycast<span style="color:#eceff4">(</span>ray<span style="color:#eceff4">,</span> world<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> collisions <span style="color:#81a1c1">=</span> world<span style="color:#eceff4">.</span>colliders<span style="color:#eceff4">.</span>map<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">(</span>aabb<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> intersection <span style="color:#81a1c1">=</span> intersect<span style="color:#eceff4">(</span>ray<span style="color:#eceff4">,</span> aabb<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> result <span style="color:#81a1c1">=</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> collider<span style="color:#81a1c1">:</span> aabb<span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> intersection<span style="color:#81a1c1">:</span> intersect<span style="color:#eceff4">(</span>ray<span style="color:#eceff4">,</span> aabb<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">};</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>result<span style="color:#eceff4">.</span>intersection<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> result<span style="color:#eceff4">.</span>distance <span style="color:#81a1c1">=</span> distance<span style="color:#eceff4">(</span>ray<span style="color:#eceff4">.</span>origin<span style="color:#eceff4">,</span> result<span style="color:#eceff4">.</span>intersection<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> result<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}).</span>filter<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">(</span>collision<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> collision<span style="color:#eceff4">.</span>intersection<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> collisions<span style="color:#eceff4">.</span>sort<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">(</span>c1<span style="color:#eceff4">,</span> c2<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> c1<span style="color:#eceff4">.</span>distance <span style="color:#81a1c1">-</span> c2<span style="color:#eceff4">.</span>distance<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// JavaScript is happy with out of bound indexing, which means this line is still +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// valid even if there are no collisions. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">return</span> collisions<span style="color:#eceff4">[</span><span style="color:#b48ead">0</span><span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>Now all we need is to fill a world with colliders and we can do arbitrary raycasts in horizontal/vertical directions and see what we hit. Let&rsquo;s now go back to our game and test this out. I&rsquo;ve added a few debug drawing helpers to visualize the rays and the distance from the collider.</p> +<!-- raw HTML omitted --> +<p><em>Click on the canvas and press <strong>A</strong> and <strong>D</strong> to move. You can also click on the <strong>JavaScript</strong> tab to see the full code for this example.</em></p> +<p>An important thing to note is that we get <code>0</code> distance when touching the wall. This is due to the <code>&lt;=</code> vs <code>&lt;</code> comparisons, which make it easier for us to detect touching walls. It might be worth nothing here that if our colliders weren&rsquo;t aligned to integer coordinates, we might run into numerical errors.</p> +<h2 id="collisions-on-all-sides">Collisions on all sides</h2> +<p>In order for the player to move around both up/down and left/right we need to detect collisions on all of the edges, so that the player stays blocked by a wall even if only a part of his collider is blocked. We do this by using two raycasts on each side, and storing the results on the player object.</p> +<p>A lot of the old collision code can be replaced with simple conditionals checking the computed distance against the velocity. Note the added <a href="https://lodash.com">lodash</a> library. While it doesn&rsquo;t provide anything we couldn&rsquo;t implement ourselves I wanted to keep the code samples on point, and implementing stuff like <code>_.flatten</code> and <code>_.min</code> wouldn&rsquo;t serve any purpose in this article.</p> +<p>We also inset each ray a little bit into the player box by a small offset <code>off</code> so that the ray doesn&rsquo;t collide with boxes next to the player in a different direction. For example, a LEFT ray could collide with the ground beneath the player, which is not what we want, as the ground collision will be detected separately by the <code>bottom</code> rays. This is why the BOTTOM LEFT ray is lifted up a little bit to avoid touching the ground.</p> +<!-- raw HTML omitted --> +<p><em>Click on the canvas and press <strong>A</strong> and <strong>D</strong> to move. You can also click on the <strong>JavaScript</strong> tab to see the full code for this example.</em></p> +<h2 id="gravity">Gravity</h2> +<p>Introducing gravity isn&rsquo;t terribly difficult. We implement it just like in real life, a force causing downward acceleration. This is easier than it sounds, acceleration simply means <em>velocity change per second</em>, which we can implement by adding vertical velocity to the player, and then updating the velocity with a gravitational constant on each frame.</p> +<!-- raw HTML omitted --> +<p><em>Click on the canvas and press <strong>A</strong> and <strong>D</strong> to move and <strong>W</strong> to jump. You can also click on the <strong>JavaScript</strong> tab to see the full code for this example.</em></p> +<p>Overall, after we have the collision rays implemented, the rest of the logic is just a matter of writing out a few conditionals that handle each case.</p> +<p>There is one bug though, which we won&rsquo;t fix. When the player moves in a perfectly diagonal direction as they&rsquo;re falling and lands on a corner of a wall the collision won&rsquo;t detect the wall and the player will fall through. This is because both of the rays on the corner are inset a small amount, causing the player to fall a little bit inside the wall. After that, the collision detection part will notice the rays start inside a wall and return <code>null</code> (because the player is technically inside the box at that point).</p> +<p><img src="https://i.imgur.com/Ah2E1ki.png" alt="player falling through a corner"></p> +<p>This goes to show that even simple as casting a few rays against boxes can have lots of edge cases that need to be handled. It is also a good argument for not implementing physics from scratch in a game that will go in productiton, as even a simple case like this isn&rsquo;t trivial to get completely right.</p> +<h2 id="conclusion">Conclusion</h2> +<p>We&rsquo;ve implemented basic collision handling and gravity. The game finally plays like a very simple platformer. We won&rsquo;t be diving into physics anymore, at least not in the sense of implementing them ourselves. Instead, we&rsquo;ll look at tweening next so that we can add a few simple animations to the game.</p> +<!-- raw HTML omitted --> +<p><strong>This article is a part 3 of the <em>Let&rsquo;s Write a 2D Platformer From Scratch Using HTML5 and JavaScript</em> series.</strong></p> +<ul> +<li><a href="https://blog.jakuba.net/2018-01-28-lets-write-a-2d-platformer-from-scratch-part-1/">Part 1: Game Loop</a></li> +<li><a href="https://blog.jakuba.net/2018-01-28-lets-write-a-2d-platformer-from-scratch-part-2/">Part 2: Rendering</a></li> +<li>Part 3: Collision Detection</li> +</ul> +<!-- raw HTML omitted --> +<h2 id="references">References</h2> +<ul> +<li><a href="http://jessewarden.com/2012/02/building-an-elevator-in-box2d.html">Elevators in Box2D</a></li> +<li><a href="https://en.wikipedia.org/wiki/Ray_casting">Ray casting</a></li> +<li><a href="https://en.wikipedia.org/wiki/Minimum_bounding_box#Axis-aligned_minimum_bounding_box">Axis-Aligned Bounding Box</a></li> +<li><a href="https://github.com/maxkueng/victor">victor.js</a></li> +<li><a href="https://github.com/toji/gl-matrix">gl-matrix</a></li> +<li><a href="https://github.com/stackgl/ray-aabb-intersection">ray-aabb-intersection</a></li> +<li><a href="https://github.com/tmpvar/ray-aabb">ray-aabb</a></li> +<li><a href="http://ncollide.org/">ncollide collision detection library for Rust</a></li> +<li><a href="https://github.com/erincatto/Box2D">Box2D physics engine</a></li> +</ul> + + + + + Let's Write a 2D Platformer From Scratch Using HTML5 and JavaScript, Part 1: Game Loop + https://blog.jakuba.net/2018-01-28-lets-write-a-2d-platformer-from-scratch-part-1/ + Sun, 28 Jan 2018 00:00:00 +0000 + + https://blog.jakuba.net/2018-01-28-lets-write-a-2d-platformer-from-scratch-part-1/ + <p><strong>This article is a part 3 of the <em>Let&rsquo;s Write a 2D Platformer From Scratch Using HTML5 and JavaScript</em> series.</strong></p> +<ul> +<li>Part 1: Game Loop</li> +<li><a href="https://blog.jakuba.net/2018-01-28-lets-write-a-2d-platformer-from-scratch-part-2/">Part 2: Rendering</a></li> +<li><a href="https://blog.jakuba.net/2018-02-01-lets-write-a-2d-platformer-from-scratch-part-3/">Part 3: Collision Detection</a></li> +</ul> +<!-- raw HTML omitted --> +<p>As far as gamedev and HTML5 goes, there are <a href="http://phaser.io/">tons</a> <a href="http://melonjs.org/">of</a> <a href="http://www.pixijs.com/">great</a> <a href="http://craftyjs.com/">game</a> <a href="https://github.com/playcanvas/engine">engines</a> <a href="https://github.com/BabylonJS/Babylon.js">already</a> <a href="https://github.com/WhitestormJS/whs.js">out</a> <a href="https://github.com/qiciengine/qiciengine">there</a>. How do we pick the right one? Look at the number of stars on GitHub? The number of contributors? The number of published games? If you&rsquo;ve looked at the previous articles on this blog, you probably know where this is heading (or read the title for that matter). We&rsquo;re going to write our own game engine first!</p> +<p>Writing a game engine is not an easy task however. We&rsquo;ll start out with just a simple 2d platformer. There won&rsquo;t be any asset pipeline, and all the rendering will be done with rectangles using a simple HTML5 Canvas API. But this does not prevent us from doing animations. We&rsquo;ll also write a simple tweening library to make animations and other time-based effects easy to add. But let&rsquo;s first begin with the game loop.</p> +<p><strong>If you&rsquo;re curious to see where this series is going</strong>, here&rsquo;s a little sneak peek of what we&rsquo;ll have at the end of <a href="https://blog.jakuba.net/2018-02-01-lets-write-a-2d-platformer-from-scratch-part-3/">part 3</a>, in which we implement collisions and gravity. Don&rsquo;t worry if it seems like a lot of code (click on the <em>JavaScript</em> tag to see the source), we&rsquo;ll build it up step by step in a way that everything should be clear along the way.</p> +<!-- raw HTML omitted --> +<p><em>Click on the canvas and press <strong>A</strong> and <strong>D</strong> to move and <strong>W</strong> to jump. You can also click on the <strong>JavaScript</strong> tab to see the full code for this example.</em></p> +<p>Deploying a game like this is easy. If you click on <em>Edit in JSFiddle</em> on the top right, you&rsquo;ll see there is a HTML and JavaScript part. The HTML only has two lines, one of which defines the <code>canvas</code>, and one defines a <code>div</code> used for debugging. That&rsquo;s all there is needed for the game to work. After that, you can just add a <code>script</code> tag with all of the code (under the <em>JavaScript</em> section) and you&rsquo;re almost ready to go. While this blog series doesn&rsquo;t rely heavily on libraries, later on we&rsquo;ll add <a href="https://lodash.com/">Lodash</a> to keep the code cleaner without writing much boilerplate. Adding Lodash is either as well, all it takes is a single line to serve it from a CDN. Overall, the page to deploy the game could look something like this:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span><span style="color:#5e81ac;font-style:italic">&lt;!DOCTYPE html&gt;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">&lt;</span><span style="color:#81a1c1">html</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">&lt;</span><span style="color:#81a1c1">head</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">&lt;</span><span style="color:#81a1c1">script</span> <span style="color:#8fbcbb">src</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;https://unpkg.com/lodash@4.17.4/lodash.js&#34;</span><span style="color:#eceff4">&gt;&lt;/</span><span style="color:#81a1c1">script</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">&lt;/</span><span style="color:#81a1c1">head</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">&lt;</span><span style="color:#81a1c1">body</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">&lt;</span><span style="color:#81a1c1">canvas</span> <span style="color:#8fbcbb">id</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;canvas&#34;</span> <span style="color:#8fbcbb">height</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;200&#34;</span> <span style="color:#8fbcbb">width</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;200&#34;</span> <span style="color:#8fbcbb">tabindex</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;1&#34;</span><span style="color:#eceff4">&gt;&lt;/</span><span style="color:#81a1c1">canvas</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">&lt;</span><span style="color:#81a1c1">div</span> <span style="color:#8fbcbb">id</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;debug-text&#34;</span><span style="color:#eceff4">&gt;&lt;/</span><span style="color:#81a1c1">div</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">&lt;</span><span style="color:#81a1c1">script</span> <span style="color:#8fbcbb">src</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;./game.js&#34;</span><span style="color:#eceff4">&gt;&lt;/</span><span style="color:#81a1c1">script</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">&lt;/</span><span style="color:#81a1c1">body</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">&lt;/</span><span style="color:#81a1c1">html</span><span style="color:#eceff4">&gt;</span> +</span></span></code></pre></div><p>But that&rsquo;s it for the spoilers! We first need to build our game, so let&rsquo;s get started.</p> +<h2 id="game-loop">Game loop</h2> +<p>The core of the game loop is calculating <code>dt</code> (or <code>deltaTime</code>), which is the time elapsed since the last frame. Every run of the game loop then updates all of the necessary logic. If we keep <code>dt</code> in seconds, we can measure all velocities as <em>per second</em> and calculate the per-frame update by simple multiplication. For example, if we intend to change <code>player.x</code> by <code>40</code> pixels per second, we can calculate the offset of a single frame by just doing <code>player.x += 40 * dt</code>. The units simply add up: <code>px/s * s = px</code>.</p> +<p>Modern browsers have a great way of implementing the game loop with the <a href="https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame"><code>requestAnimationFrame</code> function</a>. This function takes a callback, which is then called right before the next repaint of the browser window. It only calls the callback once, which means if we want our game loop to run continually we need to call <code>requestAnimationFrame</code> at the end of it. One neat feature is that the <code>requestAnimationFrame</code> function calls our callback with a <code>timestamp</code> argument, which <a href="https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#The_time_origin">basically indicates the number of milliseconds since the page has loaded</a>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> gameLoop<span style="color:#eceff4">(</span>timestamp<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Normally we would update the game logic here. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>timestamp<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Enqueue another run of the `gameLoop` function on the next browser repaint. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1">window</span><span style="color:#eceff4">.</span>requestAnimationFrame<span style="color:#eceff4">(</span>gameLoop<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// We also initially call the `gameLoop` function via `requestAnimationFrame`. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1">window</span><span style="color:#eceff4">.</span>requestAnimationFrame<span style="color:#eceff4">(</span>gameLoop<span style="color:#eceff4">);</span> +</span></span></code></pre></div><p>We can use the <code>timestamp</code> to calculate our <code>dt</code> value. The number of callbacks of <code>requestAnimationFrame</code> is usually 60 times per second (60 FPS), which amounts to about <code>16</code> milliseconds per frame. We could use <code>new Date().getTime()</code> to access the current time, but there is a newer and better API specifically intended for performance measurements. The function is <code>performance.now()</code> and also returns the number of milliseconds since the page has loaded. This is actually the same value that <code>window.requestAnimationFrame</code> passes into the callback, so we can use it to calculate the initial time before the game loop begins.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// We initialize the time of the last frame to the current time. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">var</span> lastFrame <span style="color:#81a1c1">=</span> performance<span style="color:#eceff4">.</span>now<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// window.requestAnimationFrame calls our game loop with a timestamp +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// of when the callback started being processed (in milliseconds). +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">function</span> gameLoop<span style="color:#eceff4">(</span>timestamp<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// We calculate the time since last frame in seconds +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// and update the timestamp of the last frame. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">var</span> dt <span style="color:#81a1c1">=</span> <span style="color:#eceff4">(</span>timestamp <span style="color:#81a1c1">-</span> lastFrame<span style="color:#eceff4">)</span> <span style="color:#81a1c1">/</span> <span style="color:#b48ead">1000</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> lastFrame <span style="color:#81a1c1">=</span> timestamp<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>dt<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">window</span><span style="color:#eceff4">.</span>requestAnimationFrame<span style="color:#eceff4">(</span>gameLoop<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">window</span><span style="color:#eceff4">.</span>requestAnimationFrame<span style="color:#eceff4">(</span>gameLoop<span style="color:#eceff4">);</span> +</span></span></code></pre></div><p>If we didn&rsquo;t initialize the <code>lastFrame</code> variable to <code>performance.now()</code>, we could run into an issue of our game jumping forward in time on the first frame. This could happen especially if the game doesn&rsquo;t start immediately with the page loading. To test this, try opening up the Developer Console on any web page (this one for example) and enter <code>window.requestAnimationFrame(console.log)</code> after a few seconds, and you&rsquo;ll see a fairly large number.</p> +<p>There is one problem with this approach to <code>lastFrame</code> initialization. It does not work in Chrome! It works just fine in Firefox, but <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=268213">Chrome has an open issue since 2013</a> which causes it to call the <code>gameLoop</code> with a timestamp lower than the initial value returned by <code>performance.now()</code>. In other words, the first frame would get a negative <code>dt</code>. Fortunately, the workaround isn&rsquo;t terribly difficult. We can implement simple frame limiting that caps our game loop at 60 FPS, which will also fix this issue by skipping a loop if the time that has passed is less than <code>1000 / 60</code> milliseconds.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> lastFrame <span style="color:#81a1c1">=</span> performance<span style="color:#eceff4">.</span>now<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> gameLoop<span style="color:#eceff4">(</span>timestamp<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Moving `requestAnimationFrame` won&#39;t change how the loop behaves, since JavaScript +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// runs synchronously from top to bottom and we can&#39;t get interrupted in the middle +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// of the game loop by another call caused by an earlier `requestAnimationFrame`. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1">window</span><span style="color:#eceff4">.</span>requestAnimationFrame<span style="color:#eceff4">(</span>gameLoop<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Here we simply skip the whole iteration if enough time hasn&#39;t passed yet. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>timestamp <span style="color:#81a1c1">&lt;</span> lastFrame <span style="color:#81a1c1">+</span> <span style="color:#eceff4">(</span><span style="color:#b48ead">1000</span> <span style="color:#81a1c1">/</span> <span style="color:#b48ead">60</span><span style="color:#eceff4">))</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> dt <span style="color:#81a1c1">=</span> <span style="color:#eceff4">(</span>timestamp <span style="color:#81a1c1">-</span> lastFrame<span style="color:#eceff4">)</span> <span style="color:#81a1c1">/</span> <span style="color:#b48ead">1000</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> lastFrame <span style="color:#81a1c1">=</span> timestamp<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>dt<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">window</span><span style="color:#eceff4">.</span>requestAnimationFrame<span style="color:#eceff4">(</span>gameLoop<span style="color:#eceff4">);</span> +</span></span></code></pre></div><p>One last thing we might want to do before moving on is the ability to stop the game loop. Luckily, <code>requestAnimationFrame</code> returns an ID which can later be passed to <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/cancelAnimationFrame"><code>window.cancelAnimationFrame()</code></a> to cancel the scheduled frame request. All we have to do is store this value in each iteration of the <code>gameLoop</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> lastFrame <span style="color:#81a1c1">=</span> performance<span style="color:#eceff4">.</span>now<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> requestAnimationFrameId<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> stopGameLoop<span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">window</span><span style="color:#eceff4">.</span>cancelAnimationFrame<span style="color:#eceff4">(</span>requestAnimationFrameId<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> gameLoop<span style="color:#eceff4">(</span>timestamp<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> requestAnimationFrameId <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">window</span><span style="color:#eceff4">.</span>requestAnimationFrame<span style="color:#eceff4">(</span>gameLoop<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>timestamp <span style="color:#81a1c1">&lt;</span> lastFrame <span style="color:#81a1c1">+</span> <span style="color:#eceff4">(</span><span style="color:#b48ead">1000</span> <span style="color:#81a1c1">/</span> <span style="color:#b48ead">60</span><span style="color:#eceff4">))</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> dt <span style="color:#81a1c1">=</span> <span style="color:#eceff4">(</span>timestamp <span style="color:#81a1c1">-</span> lastFrame<span style="color:#eceff4">)</span> <span style="color:#81a1c1">/</span> <span style="color:#b48ead">1000</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> lastFrame <span style="color:#81a1c1">=</span> timestamp<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>dt<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>requestAnimationFrameId <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">window</span><span style="color:#eceff4">.</span>requestAnimationFrame<span style="color:#eceff4">(</span>gameLoop<span style="color:#eceff4">);</span> +</span></span></code></pre></div><h2 id="calculating-fps-with-exponential-moving-average">Calculating FPS with exponential moving average</h2> +<p>Lastly, before moving on to implement tweening I&rsquo;d like to show one more useful thing. Game often have the ability to display FPS as the game is running. The easiest way is to use an <a href="https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average">exponential moving average</a> (<a href="https://en.wikipedia.org/wiki/Exponential_smoothing">another resource</a>) which requires no additional memory, compared to the often mentioned method of using an array of older values and doing a running average on those. If we used an array to store say <code>10</code> previous values, calculate the average off that on each frame, and push a new value on the next frame while popping the oldest value, we&rsquo;d get what is called a moving average. The key factor there is that all values have the same weight. While in this implementation of the <em>exponential smoothing</em> we put more weight on newer values and decay the older ones faster and faster (exponentially). That means if we have an exponential moving average calculated from <code>10</code> values, the newer values will contribute to the result much more than the older ones.</p> +<p>Now let&rsquo;s see how it works. First we have to pick an \(\alpha\) value which determines how quickly we decay older values. A common choice is \(\alpha = 0.1\). Then calculating the value with respect to the current frame \(FPS_{current}\) we use the value from the last calculation \(FPS_{last}\) and FPS based on the current value <code>dt</code>, which is calculated as \(\frac{1}{dt}\). Putting all this together we get:</p> +<p>$$FPS_{current} = \alpha \cdot \frac{1}{dt} + (1 - \alpha) \cdot FPS_{last}$$</p> +<p>Or alternatively (after a few basic algebraic operations):</p> +<p>$$FPS_{current} = FPS_{last} + (1 - \alpha) \cdot (\frac{1}{dt} - FPS_{last})$$</p> +<p>While this might look at a lot of complicated math, it really isn&rsquo;t. We&rsquo;re just scaling down the old value based on \(\alpha\) as we&rsquo;re adding new values. After a few iterations, the initial values was scaled down by \(\alpha\) multiple times.</p> +<p>Implementing this in code is easy, we just pick one of the formulas and write it as is, updating a <code>FPS</code> variable after each <code>dt</code> is calculated. One last note</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> lastFrame <span style="color:#81a1c1">=</span> performance<span style="color:#eceff4">.</span>now<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> requestAnimationFrameId<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> FPS <span style="color:#81a1c1">=</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">;</span> <span style="color:#616e87;font-style:italic">// It doesn&#39;t really matter what value we initialize FPS to. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">var</span> alpha <span style="color:#81a1c1">=</span> <span style="color:#b48ead">0.1</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> stopGameLoop<span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">window</span><span style="color:#eceff4">.</span>cancelAnimationFrame<span style="color:#eceff4">(</span>requestAnimationFrameId<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> gameLoop<span style="color:#eceff4">(</span>timestamp<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> requestAnimationFrameId <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">window</span><span style="color:#eceff4">.</span>requestAnimationFrame<span style="color:#eceff4">(</span>gameLoop<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>timestamp <span style="color:#81a1c1">&lt;</span> lastFrame <span style="color:#81a1c1">+</span> <span style="color:#eceff4">(</span><span style="color:#b48ead">1000</span> <span style="color:#81a1c1">/</span> <span style="color:#b48ead">60</span><span style="color:#eceff4">))</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> dt <span style="color:#81a1c1">=</span> <span style="color:#eceff4">(</span>timestamp <span style="color:#81a1c1">-</span> lastFrame<span style="color:#eceff4">)</span> <span style="color:#81a1c1">/</span> <span style="color:#b48ead">1000</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> lastFrame <span style="color:#81a1c1">=</span> timestamp<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> FPS <span style="color:#81a1c1">=</span> FPS <span style="color:#81a1c1">+</span> <span style="color:#eceff4">(</span><span style="color:#b48ead">1</span> <span style="color:#81a1c1">-</span> alpha<span style="color:#eceff4">)</span> <span style="color:#81a1c1">*</span> <span style="color:#eceff4">(</span><span style="color:#b48ead">1</span><span style="color:#81a1c1">/</span>dt <span style="color:#81a1c1">-</span> FPS<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>FPS<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>requestAnimationFrameId <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">window</span><span style="color:#eceff4">.</span>requestAnimationFrame<span style="color:#eceff4">(</span>gameLoop<span style="color:#eceff4">);</span> +</span></span></code></pre></div><h2 id="conclusion">Conclusion</h2> +<p>This concludes the first part in this series. We&rsquo;ve written a simple game loop with an FPS counter. The next article with continue with basic rendering and input handling.</p> +<!-- raw HTML omitted --> +<p><strong>This article is a part 3 of the <em>Let&rsquo;s Write a 2D Platformer From Scratch Using HTML5 and JavaScript</em> series.</strong></p> +<ul> +<li>Part 1: Game Loop</li> +<li><a href="https://blog.jakuba.net/2018-01-28-lets-write-a-2d-platformer-from-scratch-part-2/">Part 2: Rendering</a></li> +<li><a href="https://blog.jakuba.net/2018-02-01-lets-write-a-2d-platformer-from-scratch-part-3/">Part 3: Collision Detection</a></li> +</ul> +<!-- raw HTML omitted --> +<h2 id="references">References</h2> +<ul> +<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame"><code>window.requestAnimationFrame()</code></a></li> +<li><a href="https://bugs.chromium.org/p/chromium/issues/detail?id=268213">Google Chrome issue regarding <code>performance.now()</code> and <code>window.requestAnimationFrame()</code></a></li> +<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/cancelAnimationFrame"><code>window.cancelAnimationFrame()</code></a></li> +<li><a href="https://en.wikipedia.org/wiki/Exponential_smoothing">Exponential smoothing</a></li> +<li><a href="https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average">Exponential moving average</a></li> +</ul> + + + + + Let's Write a 2D Platformer From Scratch Using HTML5 and JavaScript, Part 2: Rendering + https://blog.jakuba.net/2018-01-28-lets-write-a-2d-platformer-from-scratch-part-2/ + Sun, 28 Jan 2018 00:00:00 +0000 + + https://blog.jakuba.net/2018-01-28-lets-write-a-2d-platformer-from-scratch-part-2/ + <p><strong>This article is a part 3 of the <em>Let&rsquo;s Write a 2D Platformer From Scratch Using HTML5 and JavaScript</em> series.</strong></p> +<ul> +<li><a href="https://blog.jakuba.net/2018-01-28-lets-write-a-2d-platformer-from-scratch-part-1/">Part 1: Game Loop</a></li> +<li>Part 2: Rendering</li> +<li><a href="https://blog.jakuba.net/2018-02-01-lets-write-a-2d-platformer-from-scratch-part-3/">Part 3: Collision Detection</a></li> +</ul> +<!-- raw HTML omitted --> +<p>Now that we have the game loop, we can build a small wrapper around the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">HTML5 Canvas API</a>. We&rsquo;ll start with a simple tile based map where each tile is rendered as a colored rectangle.</p> +<p>The map will be specified as an array of numbers where <code>0</code> means empty and <code>1</code> means wall. JavaScript doesn&rsquo;t have direct support for multi-dimensional arrays, which leaves us with two options. We can either store all of the values in a 1D array and calculate the index based on 2D coordinates, or we can use an <code>Array</code> of <code>Array</code>s. The second approach is simpler in terms of indexing, but works conceptually very differently. For example, there is nothing enforcing each row to have the same length as the other rows.</p> +<p>Using 1D arrays to store a 2D matrix is actually a very common pattern in lower level programming, which is why we&rsquo;ll pick it here mainly for the educational purpose. The core idea is that if we have want to access an element at <code>i</code>-th row and <code>j</code>-th column, we&rsquo;ll have to skip <code>i * ROW_LENGTH</code> elements to get to a subset of the array where the <code>i</code>-th row begins. After that, we just add the offset <code>j</code> within the <code>i</code>-th row to access the element. Since we&rsquo;re specifying map dimensions as <code>MAP_W</code> and <code>MAP_H</code> (for map width and height) we simply do <code>i * MAP_W + j</code>.</p> +<div class="highlight"><div style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"> +<table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;"> +<pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74"> 1 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74"> 2 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74"> 3 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74"> 4 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74"> 5 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74"> 6 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74"> 7 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74"> 8 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74"> 9 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">10 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">11 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">12 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">13 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">14 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">15 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">16 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">17 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">18 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">19 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">20 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">21 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">22 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">23 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">24 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">25 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">26 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">27 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">28 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">29 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">30 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">31 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">32 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">33 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">34 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">35 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">36 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">37 +</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74">38 +</span></code></pre></td> +<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"> +<pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> canvas <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">document</span><span style="color:#eceff4">.</span>getElementById<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;canvas&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> ctx <span style="color:#81a1c1">=</span> canvas<span style="color:#eceff4">.</span>getContext<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;2d&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> BOX_SIZE <span style="color:#81a1c1">=</span> <span style="color:#b48ead">20</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> MAP_W <span style="color:#81a1c1">=</span> <span style="color:#b48ead">10</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> MAP_H <span style="color:#81a1c1">=</span> <span style="color:#b48ead">10</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> drawBox<span style="color:#eceff4">(</span>color<span style="color:#eceff4">,</span> x<span style="color:#eceff4">,</span> y<span style="color:#eceff4">,</span> w<span style="color:#eceff4">,</span> h<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> ctx<span style="color:#eceff4">.</span>fillStyle <span style="color:#81a1c1">=</span> color<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> ctx<span style="color:#eceff4">.</span>fillRect<span style="color:#eceff4">(</span>x<span style="color:#eceff4">,</span> y<span style="color:#eceff4">,</span> w <span style="color:#81a1c1">||</span> BOX_SIZE<span style="color:#eceff4">,</span> h <span style="color:#81a1c1">||</span> BOX_SIZE<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> map <span style="color:#81a1c1">=</span> <span style="color:#eceff4">[</span> +</span></span><span style="display:flex;"><span> <span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> <span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> <span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> <span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> <span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> <span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> <span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> <span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> <span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> <span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> drawMap<span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">for</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">var</span> i <span style="color:#81a1c1">=</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">;</span> i <span style="color:#81a1c1">&lt;</span> MAP_H<span style="color:#eceff4">;</span> i<span style="color:#81a1c1">++</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">for</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">var</span> j <span style="color:#81a1c1">=</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">;</span> j <span style="color:#81a1c1">&lt;</span> MAP_W<span style="color:#eceff4">;</span> j<span style="color:#81a1c1">++</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Calculating the color for a tile on corrdinates [j, i]. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">var</span> color <span style="color:#81a1c1">=</span> map<span style="color:#eceff4">[</span>i <span style="color:#81a1c1">*</span> MAP_W <span style="color:#81a1c1">+</span> j<span style="color:#eceff4">]</span> <span style="color:#81a1c1">?</span> <span style="color:#a3be8c">&#34;#5d995d&#34;</span> <span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;lightblue&#34;</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// And draw it at the appropriate offset. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> drawBox<span style="color:#eceff4">(</span>color<span style="color:#eceff4">,</span> BOX_SIZE <span style="color:#81a1c1">*</span> j<span style="color:#eceff4">,</span> BOX_SIZE <span style="color:#81a1c1">*</span> i<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// Draw the player. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>drawBox<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;#612b2e&#34;</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">5</span> <span style="color:#81a1c1">*</span> BOX_SIZE<span style="color:#eceff4">);</span></span></span></code></pre></td></tr></table> +</div> +</div> +<!-- raw HTML omitted --> +<p>Later on when we put things together, each iteration of the <code>gameLoop</code> will call <code>drawMap</code> to render the background.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> gameLoop<span style="color:#eceff4">(</span>timestamp<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// ... rest of the game loop +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span> drawMap<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Draw the player. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> drawBox<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;#612b2e&#34;</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">5</span> <span style="color:#81a1c1">*</span> BOX_SIZE<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>Now all that is left to do is implement player movement.</p> +<h2 id="input-handling-and-simple-movement">Input handling and simple movement</h2> +<p>There is also no way to check if a key is being pressed in JavaScript, so we&rsquo;ll create a small global handler that stores the keypress values in a global map. Later on we can add the ability to detect key press just in the frame in which it occurred.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> keys <span style="color:#81a1c1">=</span> <span style="color:#eceff4">{};</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">window</span><span style="color:#eceff4">.</span>onkeyup <span style="color:#81a1c1">=</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">(</span>e<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> keys<span style="color:#eceff4">[</span>e<span style="color:#eceff4">.</span>keyCode<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> <span style="color:#81a1c1;font-weight:bold">false</span><span style="color:#eceff4">;</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">window</span><span style="color:#eceff4">.</span>onkeydown <span style="color:#81a1c1">=</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">(</span>e<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> keys<span style="color:#eceff4">[</span>e<span style="color:#eceff4">.</span>keyCode<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> <span style="color:#81a1c1;font-weight:bold">true</span><span style="color:#eceff4">;</span> <span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>With these, we can write an <code>updatePlayer</code> function which takes a <code>dt</code> and moves the player based on a key being pressed. We&rsquo;ll also need a <code>drawPlayer</code> function to draw the player at their position.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> player <span style="color:#81a1c1">=</span> <span style="color:#eceff4">{</span> x<span style="color:#81a1c1">:</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> y<span style="color:#81a1c1">:</span> <span style="color:#b48ead">0</span> <span style="color:#eceff4">};</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> updatePlayer<span style="color:#eceff4">(</span>dt<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Key codes for player hotkeys. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">var</span> A <span style="color:#81a1c1">=</span> <span style="color:#b48ead">65</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> W <span style="color:#81a1c1">=</span> <span style="color:#b48ead">87</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> D <span style="color:#81a1c1">=</span> <span style="color:#b48ead">68</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// The player moves at 80px per second. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">var</span> SPEED <span style="color:#81a1c1">=</span> <span style="color:#b48ead">80</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>keys<span style="color:#eceff4">[</span>A<span style="color:#eceff4">])</span> <span style="color:#eceff4">{</span> player<span style="color:#eceff4">.</span>x <span style="color:#81a1c1">-=</span> SPEED <span style="color:#81a1c1">*</span> dt<span style="color:#eceff4">;</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>keys<span style="color:#eceff4">[</span>D<span style="color:#eceff4">])</span> <span style="color:#eceff4">{</span> player<span style="color:#eceff4">.</span>x <span style="color:#81a1c1">+=</span> SPEED <span style="color:#81a1c1">*</span> dt<span style="color:#eceff4">;</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> drawPlayer<span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> drawBox<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;#612b2e&#34;</span><span style="color:#eceff4">,</span> player<span style="color:#eceff4">.</span>x<span style="color:#eceff4">,</span> player<span style="color:#eceff4">.</span>y<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><!-- raw HTML omitted --> +<h2 id="basic-collision-handling">Basic collision handling</h2> +<p>Collision handling is a complicated subject, especially if there can be arbitrary geometry present in the physics world. Luckily for us, we only have boxes of constant dimensions, and all of the walls are aligned to the tile map. The player is also the only object moving in the world, which means we only calculate collisions against the environment. If we had a multi-agent environment, we&rsquo;d need a more general concept of colliders and raycasting. But for now, we can implement the raycast by simply checking the adjacent tiles on each side.</p> +<p>Since the player can move just a single pixel, we need to actually calculate its position within a tile. We can do this by using the modulo operation <code>%</code> which returns the remainder after integer division. <code>player.x % BOX_SIZE</code> returns a value from <code>0</code> to <code>BOX_SIZE</code>, which is exactly the <code>x</code> offset of the top left corner within its containing tile. We&rsquo;ll store the tile coordinates in variables <code>tileX</code> and <code>tileY</code>.</p> +<p>We&rsquo;ll also check if the player stands next to a wall on both sides. The right side is a tiny bit trickier, because we&rsquo;re measuring the position from the top-left corner, which means we actually have to look two tiles to the right. We&rsquo;ll improve this later on when we write a more general collision handling logic.</p> +<p>Lastly, we introduce a new concept, the player&rsquo;s velocity. This can be thought of as the number of pixels the player will move within the frame (per-frame velocity). The velocity is initially based on the player&rsquo;s inputs. We then check if the player is moving in a direction of a wall, and check if the velocity is greater than the distance to the wall. If it is, the player would skip into the wall on the frame update, which is why we use <code>Math.min</code>/<code>Math.max</code> to make sure the player moves at most the distance he needs to reach the wall.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> updatePlayer<span style="color:#eceff4">(</span>dt<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Key codes for player hotkeys. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">var</span> A <span style="color:#81a1c1">=</span> <span style="color:#b48ead">65</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> W <span style="color:#81a1c1">=</span> <span style="color:#b48ead">87</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> D <span style="color:#81a1c1">=</span> <span style="color:#b48ead">68</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// The player moves at 80px per second. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">var</span> SPEED <span style="color:#81a1c1">=</span> <span style="color:#b48ead">80</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// We calculate the tile where the player is. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">var</span> tileX <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>floor<span style="color:#eceff4">(</span>player<span style="color:#eceff4">.</span>x <span style="color:#81a1c1">/</span> BOX_SIZE<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> tileY <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>floor<span style="color:#eceff4">(</span>player<span style="color:#eceff4">.</span>y <span style="color:#81a1c1">/</span> BOX_SIZE<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Player collides on the left either with the leftmost edge of the screen, +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// or with a tile which is adjacent to the left. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">var</span> possibleCollisionLeft <span style="color:#81a1c1">=</span> tileX <span style="color:#81a1c1">==</span> <span style="color:#b48ead">0</span> <span style="color:#81a1c1">||</span> map<span style="color:#eceff4">[</span>tileY <span style="color:#81a1c1">*</span> MAP_W <span style="color:#81a1c1">+</span> <span style="color:#eceff4">(</span>tileX <span style="color:#81a1c1">-</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)];</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Same for the right side. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">var</span> possibleCollisionRight <span style="color:#81a1c1">=</span> tileX <span style="color:#81a1c1">==</span> <span style="color:#eceff4">(</span>MAP_W <span style="color:#81a1c1">-</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">||</span> map<span style="color:#eceff4">[</span>tileY <span style="color:#81a1c1">*</span> MAP_W <span style="color:#81a1c1">+</span> <span style="color:#eceff4">(</span>tileX <span style="color:#81a1c1">+</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">)];</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Vertical velocity of the player. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">var</span> vx <span style="color:#81a1c1">=</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>keys<span style="color:#eceff4">[</span>A<span style="color:#eceff4">])</span> <span style="color:#eceff4">{</span> vx <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">-</span>SPEED <span style="color:#81a1c1">*</span> dt<span style="color:#eceff4">;</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>keys<span style="color:#eceff4">[</span>D<span style="color:#eceff4">])</span> <span style="color:#eceff4">{</span> vx <span style="color:#81a1c1">=</span> SPEED <span style="color:#81a1c1">*</span> dt<span style="color:#eceff4">;</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>vx <span style="color:#81a1c1">&lt;</span> <span style="color:#b48ead">0</span> <span style="color:#81a1c1">&amp;&amp;</span> possibleCollisionLeft<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// If the player is near a left wall, either move him closer to the wall +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// based on his velocity, or based on his offset within the tile if the velocity +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// would cause him to run through the wall. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> vx <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>max<span style="color:#eceff4">(</span>vx<span style="color:#eceff4">,</span> <span style="color:#81a1c1">-</span><span style="color:#eceff4">(</span>player<span style="color:#eceff4">.</span>x <span style="color:#81a1c1">%</span> BOX_SIZE<span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>vx <span style="color:#81a1c1">&gt;</span> <span style="color:#b48ead">0</span> <span style="color:#81a1c1">&amp;&amp;</span> possibleCollisionRight<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Same as for moving left, but here we have to account for the fact +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// that we use the left corner as the player&#39;s position, hence the distance +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// to the wall is computed differently. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> vx <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>min<span style="color:#eceff4">(</span>vx<span style="color:#eceff4">,</span> BOX_SIZE <span style="color:#81a1c1">-</span> <span style="color:#eceff4">(</span>player<span style="color:#eceff4">.</span>x <span style="color:#81a1c1">%</span> BOX_SIZE<span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Lastly, we have to check if the player is already standing next to a wall, +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// and nullify the vertical velocity in that case. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>vx <span style="color:#81a1c1">&gt;</span> <span style="color:#b48ead">0</span> <span style="color:#81a1c1">&amp;&amp;</span> map<span style="color:#eceff4">[</span>tileY <span style="color:#81a1c1">*</span> MAP_W <span style="color:#81a1c1">+</span> <span style="color:#eceff4">(</span>tileX <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)])</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> vx <span style="color:#81a1c1">=</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> player<span style="color:#eceff4">.</span>x <span style="color:#81a1c1">+=</span> vx<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>And here&rsquo;s how it looks inside the game: (move player with <code>A</code> and <code>D</code> keys)</p> +<!-- raw HTML omitted --> +<h2 id="conclusion">Conclusion</h2> +<p>We&rsquo;ve implemented basic input and collision handling with player movement. What we have so far serves more as a demonstration than what we&rsquo;ll end up with in the next article, as the collision handling is not flexible enough to handle more complicated player movement ansuch as gravity.</p> +<!-- raw HTML omitted --> +<p><strong>This article is a part 3 of the <em>Let&rsquo;s Write a 2D Platformer From Scratch Using HTML5 and JavaScript</em> series.</strong></p> +<ul> +<li><a href="https://blog.jakuba.net/2018-01-28-lets-write-a-2d-platformer-from-scratch-part-1/">Part 1: Game Loop</a></li> +<li>Part 2: Rendering</li> +<li><a href="https://blog.jakuba.net/2018-02-01-lets-write-a-2d-platformer-from-scratch-part-3/">Part 3: Collision Detection</a></li> +</ul> +<!-- raw HTML omitted --> +<h2 id="references">References</h2> +<ul> +<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">Canvas API</a></li> +<li><a href="https://stackoverflow.com/questions/1828613/check-if-a-key-is-down">Checking if a key is down JavaScript</a></li> +</ul> + + + + + Binary Search in JavaScript + https://blog.jakuba.net/2018-01-25-binary-search-in-javascript/ + Thu, 25 Jan 2018 10:00:00 +0100 + + https://blog.jakuba.net/2018-01-25-binary-search-in-javascript/ + <p>Binary search is an extremely useful and popular algorithm used for quickly searching in a sorted array. Binary search is even used by people in real life (outside of programming) when they play the <em>guess the number</em> game. One person thinks a number between 1 and 100, and the other person tries to guess. The response is only <em>less</em>, <em>equal</em> or <em>greater</em>. If you guess 50 and get a <em>less</em> response, you just narrowed down the search to half the interval, 1 to 50. You can keep going and guess 25. No matter if what answer you get, you either win, or narrow down the interval again to a half. This is how binary search works. We test our searched value against the element in the middle, if it&rsquo;s less than the middle element, we repeat the process on the left part, if it&rsquo;s greater than the middle element, we repeat the process on the right part. We repeat this until we get a value which is equal, at which point the search is complete.</p> +<p>The initial requirement is that the array must be sorted. Why? Because a sorted array has a simple property. If we take any two indexes <code>i</code> and <code>j</code>, if <code>i &lt;= j</code>, then <code>array[i] &lt;= array[j]</code>. This means if we know that the searched number is lower than the number at the middle index, its index must be also lower.</p> +<p>To implement to algorithm we will use two variables to store the bounds of our search area, <code>low</code> and <code>high</code>. We begin by setting <code>low = 0</code> and <code>high = array.length</code>. We calculate the middle as the average of <code>low</code> and <code>high</code>, always rounding down using the <code>Math.floor</code> function. Note that we could also use a bitwise shift to the right with the <code>&gt;&gt;</code> operator to achieve the same, but we&rsquo;ll keep the division explicit to make things easier to read. We then compare the number at the middle index to our search value. Here we can run into three different cases:</p> +<ul> +<li>If <code>array[mid] &lt; value</code>, then we need to move to the right, updating our lower bound <code>low = mid + 1</code>. We add the one because the value can&rsquo;t possibly be at <code>mid</code> (since it&rsquo;s greater than <code>array[mid]</code>), so we can skip that index entirely.</li> +<li>If <code>array[mid] &gt; value</code>, then we need to move to the left, updating our upper bound <code>high = mid</code>. Since we initialize our <code>high</code> to <code>array.length</code>, the search range does not include the <code>high</code> index (it&rsquo;s a left-closed interval), which means we don&rsquo;t need to subtract <code>1</code> from the upper bound.</li> +<li>If <code>array[mid] == value</code>, we simply return the <code>mid</code> index as a result.</li> +</ul> +<p>We keep iterating until <code>low == high</code>, at which point the search is narrowed down to a single element which must be the result if the element was initially present.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> binarySearch<span style="color:#eceff4">(</span>array<span style="color:#eceff4">,</span> value<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> low <span style="color:#81a1c1">=</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> high <span style="color:#81a1c1">=</span> array<span style="color:#eceff4">.</span>length<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">while</span> <span style="color:#eceff4">(</span>low <span style="color:#81a1c1">&lt;</span> high<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> mid <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>floor<span style="color:#eceff4">((</span>low <span style="color:#81a1c1">+</span> high<span style="color:#eceff4">)</span> <span style="color:#81a1c1">/</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>array<span style="color:#eceff4">[</span>mid<span style="color:#eceff4">]</span> <span style="color:#81a1c1">&lt;</span> value<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> low <span style="color:#81a1c1">=</span> mid <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>array<span style="color:#eceff4">[</span>mid<span style="color:#eceff4">]</span> <span style="color:#81a1c1">&gt;</span> value<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> high <span style="color:#81a1c1">=</span> mid<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> mid<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> high<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>Lastly, it&rsquo;s important to note that <strong>if we search for an element which is not present in our array, we still get an index as a return value</strong>. There are two ways to think about this. Either we think of the <code>binarySearch</code> function as searching for an index of an existing element inside the array, at which point we might want to return <code>-1</code> in case the element isn&rsquo;t found. Or we use it to calculate an index at which we should insert a new element into the array so that it remains sorted.</p> +<p>If we wanted the first variant, we could modify the binary search to check the result value before returning it.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> binarySearch<span style="color:#eceff4">(</span>array<span style="color:#eceff4">,</span> value<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> low <span style="color:#81a1c1">=</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> high <span style="color:#81a1c1">=</span> array<span style="color:#eceff4">.</span>length<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">while</span> <span style="color:#eceff4">(</span>low <span style="color:#81a1c1">&lt;</span> high<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> mid <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>floor<span style="color:#eceff4">((</span>low <span style="color:#81a1c1">+</span> high<span style="color:#eceff4">)</span> <span style="color:#81a1c1">/</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>array<span style="color:#eceff4">[</span>mid<span style="color:#eceff4">]</span> <span style="color:#81a1c1">&lt;</span> value<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> low <span style="color:#81a1c1">=</span> mid <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>array<span style="color:#eceff4">[</span>mid<span style="color:#eceff4">]</span> <span style="color:#81a1c1">&gt;</span> value<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> high <span style="color:#81a1c1">=</span> mid<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> mid<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>array<span style="color:#eceff4">[</span>high<span style="color:#eceff4">]</span> <span style="color:#81a1c1">==</span> value<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> high<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1">-</span><span style="color:#b48ead">1</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>Alternatively, we can use the first implementation to implement an insert into a sorted array which uses binary search to find the right place to insert the value. This is rather trivial, we simply find the proper index with the first version of our <code>binarySearch</code>, and then use <code>Array.splice</code> to insert the new value.</p> +<p>The original code is provided here again so that the example as a whole can be copy-pasted into a developer console (or any other JavaScript environment) for experimentation.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> binarySearch<span style="color:#eceff4">(</span>array<span style="color:#eceff4">,</span> value<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> low <span style="color:#81a1c1">=</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> high <span style="color:#81a1c1">=</span> array<span style="color:#eceff4">.</span>length<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">while</span> <span style="color:#eceff4">(</span>low <span style="color:#81a1c1">&lt;</span> high<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> mid <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>floor<span style="color:#eceff4">((</span>low <span style="color:#81a1c1">+</span> high<span style="color:#eceff4">)</span> <span style="color:#81a1c1">/</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>array<span style="color:#eceff4">[</span>mid<span style="color:#eceff4">]</span> <span style="color:#81a1c1">&lt;</span> value<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> low <span style="color:#81a1c1">=</span> mid <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>array<span style="color:#eceff4">[</span>mid<span style="color:#eceff4">]</span> <span style="color:#81a1c1">&gt;</span> value<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> high <span style="color:#81a1c1">=</span> mid<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> mid<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> high<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> binaryInsert<span style="color:#eceff4">(</span>array<span style="color:#eceff4">,</span> value<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> index <span style="color:#81a1c1">=</span> binarySearch<span style="color:#eceff4">(</span>array<span style="color:#eceff4">,</span> value<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> array<span style="color:#eceff4">.</span>splice<span style="color:#eceff4">(</span>index<span style="color:#eceff4">,</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> value<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> arr <span style="color:#81a1c1">=</span> <span style="color:#eceff4">[</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">3</span><span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>binaryInsert<span style="color:#eceff4">(</span>arr<span style="color:#eceff4">,</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>arr<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// [1, 2, 2, 3] +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span>binaryInsert<span style="color:#eceff4">(</span>arr<span style="color:#eceff4">,</span> <span style="color:#b48ead">5</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>arr<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// [1, 2, 2, 3, 5] +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span>binaryInsert<span style="color:#eceff4">(</span>arr<span style="color:#eceff4">,</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>arr<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// [0, 1, 2, 2, 3, 5] +</span></span></span></code></pre></div><h2 id="time-complexity">Time complexity</h2> +<p>The main benefit of binary search is its time complexity, which is only \(O(\log n\), compared to regular linear search (going through the whole array searching for the right index), which is \(O(n)\). Searching <code>1000000</code> elements using binary search would only take roughly <code>20</code> steps while it could take up to <code>1000000</code> steps.</p> +<p>But why is it \(O(\log n)\)? Each iteration of binary search reduces the search space by half, which means we can translate the question <em>how many steps does it take?</em> to <em>how many times can we take a half of a number until we get to 1?</em> If the array length was a power of two, meaning we could write it as \(2^k\), we could divide it by <code>2</code> exactly <code>k</code> times. If we have an arbitrary number <code>n</code> and we want to write it as \(2^k\), we can calcualte <code>k</code> with a logarithm, specifically \(\log_2 n = k\). But by the definition of the big-O notation, we don&rsquo;t need to worry about constants, and since \(\log_2 n = \frac{\log n}{\log 2}\), we can simply use \(O(\log n)\).</p> + + + + + Binary Heap (Priority Queue) in JavaScript + https://blog.jakuba.net/2018-01-24-binary-heap-priority-queue-in-javascript/ + Wed, 24 Jan 2018 10:00:00 +0100 + + https://blog.jakuba.net/2018-01-24-binary-heap-priority-queue-in-javascript/ + <p>A binary heap is a simple data structure most often used for implementing priority queues. In a more general sense, a <em>heap</em> is a tree-based data structure which satisfies the <em>heap property</em>, and a <em>binary heap</em> is a <em>heap</em> which uses a <em>binary tree</em> to store its data. Any arbitrary binary tree which satisfies the following two properties can be considered a binary heap:</p> +<ol> +<li><em>heap property</em>: If P is a parent node of N, then <code>P.key &lt;= N.key</code>, meaning the parent always has a lower key than its children. This gives us a <em>MIN</em> heap, where the root node has the minimum key of the whole heap. If we want a <em>MAX</em> heap, we simply flip the property to <code>P.key &gt;= N.key</code>. Everything that is true for a <em>MIN</em> heap is true for a <em>MAX</em> heap, so from now on, we&rsquo;ll consider a <em>MIN</em> heap only.</li> +<li>All levels of the tree are completely filled, except for the last one, which is filled from the left.</li> +</ol> +<p>Here&rsquo;s an example of a valid heap. Note that the last level is missing one element on the right. It&rsquo;s also important to distinguish that a binary heap is not a search tree. While a binary search tree satisfies the property that the left child has a lower value than the parent and right child has a higher value than the parent, a binary heap has no such property. This also means that a binary heap can not be searched.</p> +<!-- raw HTML omitted --> +<p>Here is another example, but this time of a tree which doesn&rsquo;t follow the <em>heap property</em>, and as such is not a binary heap.</p> +<!-- raw HTML omitted --> +<p>And here&rsquo;s an example of a tree which doesn&rsquo;t satisfy the same property, as the last layer is not filled from the left.</p> +<!-- raw HTML omitted --> +<p>The first property (the <em>heap property</em>) gives us the ability to access the MIN element in constant time, because it must be in the root of the tree. If the MIN was somewhere down the tree, its parent would need to have a larger key value, which would break the <em>heap property</em>. If it had a smaller value, the MIN element wouldn&rsquo;t be a true minimum, which is a contradiction with our choice of MIN as the minimum element of the whole heap.</p> +<p>The second property isn&rsquo;t so obvious, but it allows us to store the tree not as a network (graph) of nodes with edges, but as an array of numbers, where the edges can be calculated implicitly. The second property allows us to think about the binary tree as if it was a complete binary tree. There can&rsquo;t be any holes (missing elements) in the middle of the tree, only at the very right edge in the last layer. To figure out how to store the tree in an array we can first ignore the missing elements in the last layer and think about the tree as if it was complete. Here&rsquo;s how such tree might look:</p> +<!-- raw HTML omitted --> +<p>If we write it out layer by layer in an array, we simply get:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#eceff4">[</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">3</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">4</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">5</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">6</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">7</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">8</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">9</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">10</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">11</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">12</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">13</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">14</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">15</span><span style="color:#eceff4">]</span> +</span></span></code></pre></div><p>Since JavaScript arrays are <code>0</code> indexed, we can do a little trick and add a blank element to the beginning of the array, which will make every number be equal to its index. I&rsquo;m using <code>null</code> to make it clear that the first element is not really part of the data structure and only acts to fill in space. In reality, we could use something like <code>Uint32Array</code> and leave the first index set to <code>0</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#eceff4">[</span><span style="color:#81a1c1;font-weight:bold">null</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">3</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">4</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">5</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">6</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">7</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">8</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">9</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">10</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">11</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">12</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">13</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">14</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">15</span><span style="color:#eceff4">];</span> +</span></span></code></pre></div><p>If you look closely at the binary tree, <strong>you can see that the left child of each node has double the value of its parent, and the right child has double the value but plus one</strong>. Looking at <code>7</code> for example, the left child is <code>2*7 = 14</code> and the right child is <code>2*7 + 1 = 15</code>. This property is only true when we have a complete binary tree, which is exactly why the binary heap requires all but the last layers to be full.</p> +<p>Now looking back at the array, we can also see something interesting. Because we know that the root is at index <code>1</code>, its left child must be at index <code>2*1 = 2</code> and right child at index <code>2*1 + 1 = 3</code>. This will also be true for any other element, seeing that the array copies the structure of the tree. If the left child has double the value in the tree, and the array has values mapped to their index, then the left child in the array (having double the value) will be at double the index.</p> +<p>We can also get rid of the initial blank element in the array by simply shifting all results off by 1 to the right, giving us <code>2*i + 1</code> and <code>2*i + 2</code>. Let&rsquo;s try this:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#eceff4">[</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">3</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">4</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">5</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">6</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">7</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">8</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">9</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">10</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">11</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">12</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">13</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">14</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">15</span><span style="color:#eceff4">]</span> +</span></span></code></pre></div><p>The left child of <code>1</code> is <code>2</code>, which we can get to by calculating <code>2*i + 1</code>, where <code>i = 0</code> (because <code>1</code> is at <code>0</code>th index). We would get <code>2*0 + 1 = 1</code>, which is the index of its left child, the number <code>2</code>. Going further down, getting the right child of <code>2</code> (which is a <code>5</code>) we take the index of <code>2</code> (which is <code>1</code>) and plug it in the <code>2*i + 2</code> formula, giving us <code>2*1 + 2 = 4</code>, which is the index of the value <code>5</code>. Let&rsquo;s try getting the right child of <code>5</code>. We take the index, which is <code>4</code> and do <code>2*4 + 2 = 10</code>, giving us the index of the right child, the number <code>11</code>.</p> +<p>It is important to note that <strong>all the calculations are done on indexes</strong>, not the actual values. We only used numbers from <code>1</code> to <code>15</code> to make it easy to see the pattern for calculating left/right children. We could just as well do the same on a completely different binary heap, and it would work, because there isn&rsquo;t any point in the computation where the value is being used, only the index.</p> +<!-- raw HTML omitted --> +<p>We can now also see, that this way of calculating children will work even if we leave out a few nodes in the last layer, considering it is still filled from the left. Going the other way, it&rsquo;s not hard to see that if we left out one node in the middle of the tree, suddenly all of this would stop working and we would no longer have a simple formula for calculating children.</p> +<p>Lastly, we need a way to navigate back up the heap, going from children to the parent. This is easy to figure out, because if <code>left = 2*i + 1</code>, then <code>i = (left - 1) / 2</code> when going from the left child, and if <code>right = 2*i + 2</code>, then <code>i = (right - 2) / 2</code>. This gives us</p> +<p>$$\text{parent} = \frac{\text{left} - 1}{2} \text{or} \frac{\text{right} - 2}{2}$$</p> +<p>Let&rsquo;s do a little renaming first, since we&rsquo;re going from an index of the child, let&rsquo;s call that <code>i</code>, giving us a more general equation</p> +<p>$$\text{parent} = \frac{i - 1}{2} \text{or} \frac{i - 2}{2}$$</p> +<p>Now considering the expression \(\lfloor \frac{i - 1}{2} \rfloor\), equivalent to <code>Math.floor((i - 1) / 2)</code>. If we had our original <code>2*i</code> and <code>2*i + 1</code>, then <code>Math.floor(i / 2)</code> would definitely work, because we&rsquo;re basically getting rid of the <code>+1</code> in the second case. In the more complicated <code>2*i + 1</code> and <code>2*i + 2</code> we can think of the <code>i - 1</code> as moving to the simpler case, and then using the same <code>floor</code> function.</p> +<h2 id="navigating-a-binary-heap-in-an-array">Navigating a binary heap in an Array</h2> +<p>Let&rsquo;s create an <code>Array</code> for the following heap:</p> +<!-- raw HTML omitted --> +<p>We simply write down the numbers going layer by layer, left to right, getting:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// indexes: 0 1 2 3 4 5 +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">var</span> heap <span style="color:#81a1c1">=</span> <span style="color:#eceff4">[</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">3</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">5</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">4</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">9</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">6</span><span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> left<span style="color:#eceff4">(</span>i<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#b48ead">2</span><span style="color:#81a1c1">*</span>i <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">;</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> right<span style="color:#eceff4">(</span>i<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#b48ead">2</span><span style="color:#81a1c1">*</span>i <span style="color:#81a1c1">+</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">;</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> parent<span style="color:#eceff4">(</span>i<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>floor<span style="color:#eceff4">((</span>i <span style="color:#81a1c1">-</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">/</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">);</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">[</span>left<span style="color:#eceff4">(</span><span style="color:#b48ead">0</span><span style="color:#eceff4">)]);</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 3 +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">[</span>right<span style="color:#eceff4">(</span><span style="color:#b48ead">0</span><span style="color:#eceff4">)]);</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 5 +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// We can even use .indexOf() to make this a bit clearer +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">[</span>left<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">.</span>indexOf<span style="color:#eceff4">(</span><span style="color:#b48ead">3</span><span style="color:#eceff4">))]);</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 4 +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">[</span>right<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">.</span>indexOf<span style="color:#eceff4">(</span><span style="color:#b48ead">3</span><span style="color:#eceff4">))]);</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 9 +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">[</span>left<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">.</span>indexOf<span style="color:#eceff4">(</span><span style="color:#b48ead">5</span><span style="color:#eceff4">))]);</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 6 +</span></span></span></code></pre></div><p>After this, it should be crystal clear that we can think in terms of a tree, but do the actual operations on an <code>Array</code> representing the same thing.</p> +<h2 id="heap-operations">Heap operations</h2> +<p>Now that we understand how to store the heap, we can take a look at the operations the heap supports, their time complexity, and how to implement them. First, here&rsquo;s an overview of the supported operations:</p> +<ul> +<li><code>Min()</code>: Returns the MIN element, that is the one with the lowest key, \(O(1)\).</li> +<li><code>Insert(key, value)</code>: Inserts a value into the heap under a given key, \(O(\log n)\).</li> +<li><code>ExtractMin()</code>: Returns the MIN element and removes it from the heap, \(O(\log n)\).</li> +</ul> +<p>Earlier in this article, we implemented the heap as an <code>Array</code> of <code>Number</code>s. But in real life, we will almost always want to store actual objects in the heap, and order them by a given key. This can be done in multiple ways. We can either store an <code>Array</code> of objects that look something like <code>{ key: X, value: the_actual_object }</code>, or we can use a mapping function that the heap uses to map each element to its key. For example <code>function(user) { return user.id; }</code> could be used to map users to their respective <code>user.id</code>. I&rsquo;m going to assume the first example, since it makes the implementation a bit shorter, but both ways should be equally easy to implement.</p> +<h3 id="min">Min()</h3> +<p>Returning the MIN element is an easy operation thanks to the heap property. We already know it is present in the root, which means we simply return the element at index <code>0</code> in our array. The time complexity of this operations is \(O(1)\).</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> min<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Note that we&#39;re expecting the `{ key: X, value: the_actual_object }` format, +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// which is why we&#39;re returning `.value` here. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">return</span> heap<span style="color:#eceff4">[</span><span style="color:#b48ead">0</span><span style="color:#eceff4">].</span>value<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><h3 id="insertkey-value">Insert(key, value)</h3> +<p>Adding an element is rather simple. First we add it to the end of our <code>Array</code>, which is semantically equivalent to adding a new leaf to the last layer of the tree (as far left as possible). This however breaks the <em>heap property</em>, saying that the key of each node must be lower than the keys of its children. We can easily fix this by <em>bubbling</em> the newly added node up, checking if its key is lower than its parent, and swapping them if it is.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> insert<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">,</span> key<span style="color:#eceff4">,</span> value<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> node <span style="color:#81a1c1">=</span> <span style="color:#eceff4">{</span> key<span style="color:#81a1c1">:</span> key<span style="color:#eceff4">,</span> value<span style="color:#81a1c1">:</span> value <span style="color:#eceff4">};</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> heap<span style="color:#eceff4">.</span>push<span style="color:#eceff4">(</span>node<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> index <span style="color:#81a1c1">=</span> heap<span style="color:#eceff4">.</span>length <span style="color:#81a1c1">-</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">while</span> <span style="color:#eceff4">(</span>index <span style="color:#81a1c1">&gt;</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> parentIndex <span style="color:#81a1c1">=</span> parent<span style="color:#eceff4">(</span>index<span style="color:#eceff4">);</span> <span style="color:#616e87;font-style:italic">// here comes the `Math.floor((i - 1) / 2)` +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>heap<span style="color:#eceff4">[</span>index<span style="color:#eceff4">].</span>key <span style="color:#81a1c1">&lt;</span> heap<span style="color:#eceff4">[</span>parentIndex<span style="color:#eceff4">].</span>key<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> tmp <span style="color:#81a1c1">=</span> heap<span style="color:#eceff4">[</span>index<span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span> heap<span style="color:#eceff4">[</span>index<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> heap<span style="color:#eceff4">[</span>parentIndex<span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span> heap<span style="color:#eceff4">[</span>parentIndex<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> tmp<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> index <span style="color:#81a1c1">=</span> parentIndex<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// We can stop up-propagating since the rest of the tree already +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// obeys the heap property and the upper nodes would have even lower keys +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// than our direct ancestor. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">break</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> heap <span style="color:#81a1c1">=</span> <span style="color:#eceff4">[];</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>insert<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">,</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;b&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>insert<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">,</span> <span style="color:#b48ead">3</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;c&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>insert<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">,</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;a&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 0: {key: 1, value: &#34;a&#34;} +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 1: {key: 3, value: &#34;c&#34;} +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 2: {key: 2, value: &#34;b&#34;} +</span></span></span></code></pre></div><p>We can see that <code>1</code> is in the root as expected, <code>3</code> is as the left child, and <code>2</code> is as the right child. This is because after the first two inserts, right when we added <code>1</code> to the leaf the heap looked like this (the nodes are labeled as <code>key[value]</code> for simplicity):</p> +<!-- raw HTML omitted --> +<p>But the <code>insert</code> call runs the up-propagation, it swaps <code>2</code> and <code>1</code>, creating the final shape of the tree.</p> +<!-- raw HTML omitted --> +<p>Adding <code>0</code> to the heap would cause yet another round of up-propagation.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> heap <span style="color:#81a1c1">=</span> <span style="color:#eceff4">[];</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>insert<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">,</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;b&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>insert<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">,</span> <span style="color:#b48ead">3</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;c&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>insert<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">,</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;a&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>insert<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">,</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;~&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 0: {key: 0, value: &#34;~&#34;} +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 1: {key: 1, value: &#34;a&#34;} +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 2: {key: 2, value: &#34;b&#34;} +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 3: {key: 3, value: &#34;c&#34;} +</span></span></span></code></pre></div><p>Initially before the up-propagation the heap would look like this, breaking the heap property:</p> +<!-- raw HTML omitted --> +<p>but after up-propagating the <code>0[~]</code> element up we get a proper MIN-heap:</p> +<!-- raw HTML omitted --> +<p>Because of the second property of a binary heap, we can think of a complete binary tree of the same depth as an upper bound on the shape of the heap. From this, we can easily derive that the depth of a complete binary tree is \(\log n\). The <code>Insert</code> operation only traverses the tree once, going from a leaf to the root, which is \(\log n\) layers. The whole <code>Insert</code> operation is thus also \(O(\log n)\).</p> +<h3 id="extractmin">ExtractMin()</h3> +<p>Removing the MIN element is easier than it might seem at first. We swap the root node with the last element on the last level, remove the last element from the <code>Array</code> altogether (this removes the MIN element from the heap), and then propagate the new root down to fix the <em>heap property</em>. We have to be a bit careful here though. While propagating up only required to compare with the parent, when propagating down we have to check against both the children, and swap with the smaller one. Why? A simple example will explain:</p> +<!-- raw HTML omitted --> +<p>Let&rsquo;s say <code>a &gt; b</code> and <code>a &gt; c</code>, which means <code>a</code> needs to be propagated down. If we picked one of the children at random (or always the left one for example), we could break the heap property. Here&rsquo;s how the tree would look after swapping <code>a</code> with <code>b</code>.</p> +<!-- raw HTML omitted --> +<p>We might have fixed the relationship between <code>a</code> and <code>b</code>, but if we also had <code>b &gt; c</code> originally, we would still have a tree that does not satisfy the heap property. We can fix this easily by looking at both the children, comparing them against each other, and swapping with the smaller one. That way, we would&rsquo;ve swapped <code>a</code> with <code>c</code>, making <code>c</code> the new MIN root. This would be fine, because <code>c &lt; b</code>.</p> +<p>To clarify this better, let&rsquo;s look at an example of doing the whole <code>ExtractMin()</code> operation on a small heap.</p> +<!-- raw HTML omitted --> +<p>First <code>ExtractMin()</code> swaps the root with the last element in the last layer.</p> +<!-- raw HTML omitted --> +<p>Then it removes the <code>1</code> from the heap altogether, but still having the <em>heap property</em> broken.</p> +<!-- raw HTML omitted --> +<p>Swapping down with the smaller of the two children at the second layer. Note that this is legal, because <code>2 &lt; 3</code>.</p> +<!-- raw HTML omitted --> +<p>And continuing further down, until there are no more swaps needed, or until it reachest the last layer.</p> +<!-- raw HTML omitted --> +<p>Knowing how the operation works, we can implement it in a fairly straightforward way. This example also includes all of the necessary above code to make it easier to test out in the console and understand the heap as a whole.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> left<span style="color:#eceff4">(</span>i<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#b48ead">2</span><span style="color:#81a1c1">*</span>i <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">;</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> right<span style="color:#eceff4">(</span>i<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#b48ead">2</span><span style="color:#81a1c1">*</span>i <span style="color:#81a1c1">+</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">;</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> parent<span style="color:#eceff4">(</span>i<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>floor<span style="color:#eceff4">((</span>i <span style="color:#81a1c1">-</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">/</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">);</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> min<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Note that we&#39;re expecting the `{ key: X, value: the_actual_object }` format, +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// which is why we&#39;re returning `.value` here. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">return</span> heap<span style="color:#eceff4">[</span><span style="color:#b48ead">0</span><span style="color:#eceff4">].</span>value<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> insert<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">,</span> key<span style="color:#eceff4">,</span> value<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> node <span style="color:#81a1c1">=</span> <span style="color:#eceff4">{</span> key<span style="color:#81a1c1">:</span> key<span style="color:#eceff4">,</span> value<span style="color:#81a1c1">:</span> value <span style="color:#eceff4">};</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> heap<span style="color:#eceff4">.</span>push<span style="color:#eceff4">(</span>node<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> index <span style="color:#81a1c1">=</span> heap<span style="color:#eceff4">.</span>length <span style="color:#81a1c1">-</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">while</span> <span style="color:#eceff4">(</span>index <span style="color:#81a1c1">&gt;</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> parentIndex <span style="color:#81a1c1">=</span> parent<span style="color:#eceff4">(</span>index<span style="color:#eceff4">);</span> <span style="color:#616e87;font-style:italic">// here comes the `Math.floor((i - 1) / 2)` +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>heap<span style="color:#eceff4">[</span>index<span style="color:#eceff4">].</span>key <span style="color:#81a1c1">&lt;</span> heap<span style="color:#eceff4">[</span>parentIndex<span style="color:#eceff4">].</span>key<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> tmp <span style="color:#81a1c1">=</span> heap<span style="color:#eceff4">[</span>index<span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span> heap<span style="color:#eceff4">[</span>index<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> heap<span style="color:#eceff4">[</span>parentIndex<span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span> heap<span style="color:#eceff4">[</span>parentIndex<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> tmp<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> index <span style="color:#81a1c1">=</span> parentIndex<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// We can stop up-propagating since the rest of the tree already +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// obeys the heap property and the upper nodes would have even lower keys +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// than our direct ancestor. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">break</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> extractMin<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> result <span style="color:#81a1c1">=</span> min<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// If there is only one element in the heap, that being the minimum, we can just clear it. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>heap<span style="color:#eceff4">.</span>length <span style="color:#81a1c1">==</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> heap<span style="color:#eceff4">.</span>splice<span style="color:#eceff4">(</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> result<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// We copy the last element to the root and remove the last element. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// There is no need to do an actual swap as we showed in the examples above, +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// since the last element is going to get removed immediately afterwards. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> heap<span style="color:#eceff4">[</span><span style="color:#b48ead">0</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> heap<span style="color:#eceff4">[</span>heap<span style="color:#eceff4">.</span>length <span style="color:#81a1c1">-</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span> heap<span style="color:#eceff4">.</span>splice<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">.</span>length <span style="color:#81a1c1">-</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> bubbleDown<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">,</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> result<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> bubbleDown<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">,</span> index<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> leftIndex <span style="color:#81a1c1">=</span> left<span style="color:#eceff4">(</span>index<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> rightIndex <span style="color:#81a1c1">=</span> right<span style="color:#eceff4">(</span>index<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> smallest <span style="color:#81a1c1">=</span> index<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>leftIndex <span style="color:#81a1c1">&lt;</span> heap<span style="color:#eceff4">.</span>length <span style="color:#81a1c1">&amp;&amp;</span> heap<span style="color:#eceff4">[</span>leftIndex<span style="color:#eceff4">].</span>key <span style="color:#81a1c1">&lt;</span> heap<span style="color:#eceff4">[</span>smallest<span style="color:#eceff4">].</span>key<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> smallest <span style="color:#81a1c1">=</span> leftIndex<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>rightIndex <span style="color:#81a1c1">&lt;</span> heap<span style="color:#eceff4">.</span>length <span style="color:#81a1c1">&amp;&amp;</span> heap<span style="color:#eceff4">[</span>rightIndex<span style="color:#eceff4">].</span>key <span style="color:#81a1c1">&lt;</span> heap<span style="color:#eceff4">[</span>smallest<span style="color:#eceff4">].</span>key<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> smallest <span style="color:#81a1c1">=</span> rightIndex<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>index <span style="color:#81a1c1">!=</span> smallest<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> tmp <span style="color:#81a1c1">=</span> heap<span style="color:#eceff4">[</span>index<span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span> heap<span style="color:#eceff4">[</span>index<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> heap<span style="color:#eceff4">[</span>smallest<span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span> heap<span style="color:#eceff4">[</span>smallest<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> tmp<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> bubbleDown<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">,</span> smallest<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> heap <span style="color:#81a1c1">=</span> <span style="color:#eceff4">[];</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>insert<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">,</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;b&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>insert<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">,</span> <span style="color:#b48ead">3</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;c&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>insert<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">,</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;a&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>insert<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">,</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;~&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>extractMin<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// &#34;~&#34; +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 0: {key: 1, value: &#34;a&#34;} +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 1: {key: 3, value: &#34;c&#34;} +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 2: {key: 2, value: &#34;b&#34;} +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>extractMin<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// &#34;a&#34; +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 0: {key: 2, value: &#34;b&#34;} +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 1: {key: 3, value: &#34;c&#34;} +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>extractMin<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// &#34;b&#34; +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 0: {key: 3, value: &#34;c&#34;} +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>extractMin<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// &#34;c&#34; +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>heap<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// [] +</span></span></span></code></pre></div><p>Same as with the <code>Insert</code> case, <code>ExtractMin</code> also traverses the tree at most once, going from the root to a leaf, which means the time complexity is also \(O(\log n)\).</p> +<h2 id="conclusion">Conclusion</h2> +<p>In the beginning we mentioned that a binary heap is also often used as a priority queue. A good example here might be a task scheduler which always takes the task with the highest priority and runs it. Adding new tasks to the priority queue and extracting the highest priority one would both have \(O(\log n)\) time complexity, which makes it very fast even as the number of tasks grows larger. Another thing to note, the <code>Array</code> based implementation has all the benefits of a tree data structure without having a bunch of objects floating around on the memory heap.</p> +<p>Lastly, the binary heap is not the only heap there is, even though it&rsquo;s probably the most common one. Two other examples are <a href="https://nlogn.xyz/2018/01/23/fibonacci-and-binomial-heap.html">Binomial and Fibonacci heaps</a>, which are very different from the binary heap, and provide some very interesting time complexities on their operations. For example, inserting an element into a Fibonacci heap is \(O(1)\). There are also two operations which we didn&rsquo;t cover in this article, <code>Decrease</code> which changes the key of an element in the heap, and <code>Merge</code> which takes two heaps and merges them together into one. The reason we didn&rsquo;t cover them is that <code>Decrease</code> requires some additional handling to be useful, and <code>Merge</code> in and of itself isn&rsquo;t so common. But those two are also an area where a Fibonacci heap provides constant time complexity, while the binomial heap is only \(O(\log n)\) for <code>Decrease</code> and \(O(n)\) for <code>Merge</code>.</p> +<h2 id="references">References</h2> +<ul> +<li><a href="https://en.wikipedia.org/wiki/Binary_heap">Binary heap on Wikipedia</a></li> +<li><a href="https://nlogn.xyz/2018/01/23/fibonacci-and-binomial-heap.html">Binomial and Fibonacci heap notes</a></li> +</ul> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> + + + + + Few notes on the Binomial and Fibonacci heaps + https://blog.jakuba.net/2018-01-23-fibonacci-and-binomial-heap/ + Tue, 23 Jan 2018 10:00:00 +0100 + + https://blog.jakuba.net/2018-01-23-fibonacci-and-binomial-heap/ + <p>Having just implemented and tested a Fibonacci heap on a large dataset I thought I&rsquo;d write up a bit about it, mostly so that I can reference this post later in the future, and to help me remember things I&rsquo;ve learned better. Note that this blog post is not a tutorial on how to implement a Binomial/Fibonacci heap.</p> +<p>First, let&rsquo;s begin with a few definitions. Throughout the article we&rsquo;ll be talking about min-heaps. The <em>heap property</em> of a tree says that the value in each node is less than or equal to the value of its children. It doesn&rsquo;t say which values go to the left and which go to the right, so it doesn&rsquo;t help us with searching. It only tells us that the minimum of any subtree is in its root. Also note that we are not restricting ourselves just to binary trees, this property works for any kind of tree.</p> +<h2 id="binomial-heap">Binomial heap</h2> +<p>Before we can define a binomial heap, we need to define a <em>binomial tree</em>. We&rsquo;ll use a recursive definition.</p> +<ol> +<li>A binomial tree of rank <strong>0</strong> is a single node without any children.</li> +<li>A binomial tree of rank <strong>k</strong> is a tree where the root has exactly <strong>k</strong> children, which are, going from left to right, binomial trees of rank <strong>0..k-1</strong>.</li> +</ol> +<p>To make things a little more confusing, here&rsquo;s a picture from wikipedia, which uses uses a reverse order, putting children of lower rank to the right. Both definitions are equivalent.</p> +<p><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Binomial_Trees.svg/500px-Binomial_Trees.svg.png" alt="binomial tree"></p> +<p>Before we move onto the binomial heap, let us prove a small property which will be useful later. <em>A binomial tree of rank $k$ has $2^k$ nodes.</em> For k=0 we get $2^0 = 1$, which is true. Now taking $k&gt;0$, we know that a binomial tree of rank $k-1$ has $2^{k-1}$ nodes. We also know, that we can use two trees of rank $k-1$ and combine them into a binomial tree of rank $k$.</p> +<p><img src="https://i.imgur.com/8MOL7hJ.png" alt="merging binomial trees"></p> +<p>If we do that, we get $2 \cdot 2^{k-1} = 2^k$ nodes in total. This shows that the number of children is logarithmic in the total number of nodes. Since increasing the rank by one increases the depth of the tree by one as well, we get that a binomial tree with $n$ nodes has the depth of $O(\log n)$ and also has $O(\log n)$ children at the root.</p> +<p>A small sidenote, when we merge two binomial trees, in order to preserve the heap property, we have to put the one with a higher value in its root under the one with the lower value.</p> +<p>Now moving onto a <strong>binomial heap</strong>, we define it as a list of binomial trees T1,&hellip;,Tk, which are sorted by their rank, each rank from 0 to $k$ occurs at most once, and each tree obeys the heap property.</p> +<p>The operations we want from the binomial heap are the following:</p> +<ul> +<li><strong>Min</strong>: Finding the minimum, which can be either obtained in $O(\log n)$ by iterating the roots, or in $O(1)$ by keeping a separate minimum pointer and updating it along the other operations.</li> +<li><strong>Merge</strong>: Taking two binomial heaps and merging them together, we simply iterate both lists, looking at the same rank at a time &hellip; if both heaps contain a tree of the same rank, we merge them together, creating a tree of one rank higher. We keep doing if there&rsquo;s also a tree of one rank higher, much like we would carry over 1 in binary addition. This whole operating is $O(\log n)$, as it does the same exact operations as binary addition does, which can be shown as $O(\log n)$ using basic amortized analysis.</li> +<li><strong>Insert</strong>: Adding a single item into the heap. We do this by creating a singleton heap with just one element and merging it into our heap. By definition this is also $O(\log n)$.</li> +<li><strong>Build</strong>: Building a binomial heap from a list of $n$ elements. Unlike in a binary heap, we can simply call <strong>Insert</strong> for each element. I won&rsquo;t go into why, but the complexity is just $O(n)$, not $O(n \log n)$ as we could expect.</li> +<li><strong>ExtractMin</strong>: Removing a minimum from the heap, we take the tree with the minimum value at its root, remove it from the heap, create a new heap into which we insert all of its children, and merge that heap back into our initial heap. The whole operation is again $O(\log n)$.</li> +</ul> +<h2 id="lazy-binomial-heap">Lazy binomial heap</h2> +<p>We can go a bit further and make our binomial heap lazy. This will help us improve the amortized time of some of the operations. The only change we&rsquo;re going to make is allow multiple trees of the same rank to co-exist in our binomial heap.</p> +<p>We&rsquo;ll simplify our <strong>Merge</strong> operation so that it works in constant time. Instead of doing all of those complicated operations, we simply take the both lists of trees of both heaps, and concatenate them together. This can be done in $O(1)$ when using double linked lists. (Note that the minimum pointer should be updated to the minimum of both heaps when doing this).</p> +<p>We also modify our <strong>ExtractMin</strong> operation so that it performs a new operation called <strong>Consolidation</strong>. This will fix our heap so that it again looks like a binomial heap. In a nutshell, we&rsquo;ll do a bucket sort on the lists of trees in our heap, and then merge trees in each bucket until there&rsquo;s only one left (note that when we merge two trees we create a tree of a higher rank, so we move it one bucket up). Iterating the buckets from lower to higher ranks will result in a bucket lists where each bucket contains zero or one tree. We can convert this back to a binomial heap.</p> +<p>The whole trick is that the consolidation itself is $O(\log n)$ (amortized), so we keep the amortized complexity of <strong>ExtractMin</strong>, but improve the complexity of <strong>Insert</strong> and <strong>Merge</strong> to $O(1)$. Also note that the worst case time of <strong>ExtractMin</strong> is $O(n)$.</p> +<h2 id="fibonacci-heap">Fibonacci heap</h2> +<p>Going even further, we want our heap to also support the <strong>Decrease</strong> operation, which takes a pointer to a node and changes its key to a specific value. As doing this blindly could break the heap property, we have to do some tweaking to our data structure.</p> +<p>A regular binomial heap can do a <strong>Decrease</strong> in $O(\log n)$ by simply propagating the decreased element as far up to the root as needed to maintain the heap property. But our Fibonacci heap will be able to do this in just $O(1)$!.</p> +<p>To allow this, we tweak our definition of the binomial heap. We keep the heap ordering on our trees, but we don&rsquo;t require them to be binomial. All of the above mentioned operations will be identical to the lazy binomial heap, with the exception of <strong>Decrease</strong>. We&rsquo;ll also be keeping an additional flag on each node, which says if the node is <strong>marked</strong>.</p> +<p>When <strong>Decrease</strong> is called on a node, we check if it changes the keys in such the parent node now has a higher value. If not, we stop right here as the tree keeps the heap property. If the parent now has a higher value, we <strong>Cut</strong> the subtree at the changed note (including the changed node, acting as a root).</p> +<p>The <strong>Cut</strong> operation takes the subtree, removes it from its parent, and <strong>Insert</strong>s it back into the heap. If the parent was <strong>marked</strong>, we recursively call <strong>Cut</strong> on the parent. If the parent wasn&rsquo;t <strong>marked</strong>, we mark it and end right there.</p> +<p>This means our first <strong>Decrease</strong> will simply take the subtree at the decreased note, mark its parent, and insert the subtree back into the heap. If we then call a second <strong>Decrease</strong> under the same parent node, we will end up <strong>Cut</strong>ting the parent as well. This prevents the tree from becoming too degenerate.</p> +<p>The most interesting part here (which I&rsquo;m however not going to prove), is that the amortized cost of <strong>Cut</strong> is $O(1)$, and the amortized cost of <strong>Decrease</strong> is also $O(1)$. This makes for a very interesting data structure, in which all operations except for the <strong>ExtractMin</strong> run in amortized constant time.</p> +<h2 id="conclusion">Conclusion</h2> +<p>I do realize that I&rsquo;ve skipped most of the amortized analysis, and simplified a few things, but this article mostly serves as a mental refresher for people already somewhat familiar with the Fibonacci heap. For a complete reference, check out <a href="https://en.wikipedia.org/wiki/Fibonacci_heap">the references at the Wikipedia page</a>.</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> + + + + + Bloom filter in JavaScript + https://blog.jakuba.net/2018-01-07-bloom-filter-in-javascript/ + Thu, 18 Jan 2018 10:00:00 +0100 + + https://blog.jakuba.net/2018-01-07-bloom-filter-in-javascript/ + <!-- raw HTML omitted --> +<p><strong><em>This article assumes basic familiarty with bit vectors. If you&rsquo;re unsure how they work or need a refresher, check out <a href="https://blog.jakuba.net/2018/01/17/bit-vector-in-javascript.html">the previous article about bit vectors</a> which goes in depth both in explaining how they work, and how to implement one.</em></strong></p> +<p>A Bloom filter is a simple yet powerful data structure. It allows you to answer the question <em>have you seen this before?</em> in a very fast and memory efficient way. Unlike a regular set, a Bloom filter only needs to store a few bits per item instead of storing the whole thing. The trick is, a Bloom filter will be able to tell you if something is <em>not present in the set</em> with 100% certainty, but if you ask it if something <em>is present in the set</em>, you might get a false positive. That means the response could be true, even if the item was never stored in the set.</p> +<p>To explain things, let&rsquo;s first do a simple example. Consider we&rsquo;re taking random numbers as input and checking if we&rsquo;ve already seen a given number. We could use an array and store the numbers and check its contents whenever needed.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> arr <span style="color:#81a1c1">=</span> <span style="color:#eceff4">[];</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// inserting a few elements in the array +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>arr<span style="color:#eceff4">.</span>push<span style="color:#eceff4">(</span><span style="color:#b48ead">3</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>arr<span style="color:#eceff4">.</span>push<span style="color:#eceff4">(</span><span style="color:#b48ead">5</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// and checking for presence +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>arr<span style="color:#eceff4">.</span>indexOf<span style="color:#eceff4">(</span><span style="color:#b48ead">3</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">!==</span> <span style="color:#81a1c1">-</span><span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>arr<span style="color:#eceff4">.</span>indexOf<span style="color:#eceff4">(</span><span style="color:#b48ead">4</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">!==</span> <span style="color:#81a1c1">-</span><span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span></code></pre></div><p><em><code>arr.indexOf(...)</code> returns the index of an element in the array if found, and <code>-1</code> if the element was not present in the array.</em></p> +<p>This approach works, but it has a few issues. Firstly, <code>indexOf</code> needs to traverse the entire array to see if an element is present (\(O(n)\) time complexity), which means the bigger the array, the longer it will take. And second, we&rsquo;re also using extra memory for each element we add to the array. This might seem dumb at first, considering we haven&rsquo;t gotten to the Bloom filter part, but read on to see how we can save a lot of memory with a probabilistic approach. But first, let&rsquo;s try fixing the lookup time by switching to a hash table. We could use JavaScript&rsquo;s builtin objects to store a truthy value.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> table <span style="color:#81a1c1">=</span> <span style="color:#eceff4">{};</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>table<span style="color:#eceff4">[</span><span style="color:#b48ead">3</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> <span style="color:#81a1c1;font-weight:bold">true</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span>table<span style="color:#eceff4">[</span><span style="color:#b48ead">5</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> <span style="color:#81a1c1;font-weight:bold">true</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>table<span style="color:#eceff4">[</span><span style="color:#b48ead">3</span><span style="color:#eceff4">]);</span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>table<span style="color:#eceff4">[</span><span style="color:#b48ead">4</span><span style="color:#eceff4">]);</span> +</span></span></code></pre></div><p>This helps us with the lookup time to an average constant time \(O(1)\). The thing is, if we were to count a lot of numbers, it would take up a lot of memory. Considering we&rsquo;re only storing numbers here, you might be thinking that we could use a bit vector, which would only take 1 bit per number. If we were to store something like IPv4 addresses encoded as 32-bit integers, we would need to allocate a 128MB bit vector. That might still be feasible, as the set of possible values is still only 32 bits. Increasing this to IPv6 (which are 128-bit integers), the bit vector would be way too big (rougly \(10^{36}\) bytes).</p> +<p>Here comes the interesting part though, what if we only intend to store a portion of the numbers. If it was small enough, we could simply store them in an array. If it was bigger, we&rsquo;d probably use a hash table or ideally a set data structure. But what if we need to store lots of them?</p> +<p>Storing 5 million IPv6 addresses (128bit numbers) would take up around 76MB of memory. That might not seem like a huge deal if all you&rsquo;re doing is managing which IPv6 address you&rsquo;ve seen before. But what if this is part of a side calculation that isn&rsquo;t particularly important? Or what if you need to store even more? The storage requirements grow linearly together with each address. At 50 million we&rsquo;d be closing in 1GB of memory.</p> +<h2 id="using-a-probabilistic-approach-to-save-memory">Using a probabilistic approach to save memory</h2> +<p>If we&rsquo;re willing to relax our requirements on the data structure, we can save quite a bit of memory. The original bit vector approach is great in terms of memory, but fails when the set of possible values is too large, as we need to pre-allocate a slot for each possible value. But what if we allowed multiple values to share the same slot?</p> +<p>We can use a simple hash function to calculate the position in the bit vector, which allows us to have a bit vector that is smaller than the set of possible values. If we have 100 possible values, but only 10 bits, we can use a <em>modulo 10</em> hash function to set the proper bit to <code>true</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> hash<span style="color:#eceff4">(</span>num<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> num <span style="color:#81a1c1">%</span> <span style="color:#b48ead">10</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>This approach does decrease the amount of memory required by 10x, but it&rsquo;s also easy to see that collisions in the hash function can occur rather easily. For example <code>1</code>, <code>11</code>, <code>21</code>, <code>31</code>, &hellip; all have the same hash value. At first this seems like our data structure is completely broken and can&rsquo;t tell us anything useful, but something interesting happens here.</p> +<p>When we query the data structure, there are two cases that can happen:</p> +<ol> +<li>The queried bit is <code>true</code>, which means the number we used to calculate the hash might have been used to set it, or it could have been a different number with the same hash.</li> +<li>The queried bit is <code>false</code>, which menas the number was never present in the set! <strong>There is no way a different number could be used to set any bit to <code>false</code>.</strong></li> +</ol> +<p>There is a big difference between cases 1) and 2). While the first case gives a probabilistic response with a possible false positive (getting <code>true</code> while the answer should be <code>false</code>), the second case is always 100% correct. If we get a <code>false</code>, the element definitely isn&rsquo;t in the set!</p> +<p>Before we move on to how an actual bloom filter works, let&rsquo;s see a few examples where a data structure that can return false positives but never returns false negatives can be useful:</p> +<ul> +<li>Tracking which pages/articles/profiles/websites a user has seen and which he hasn&rsquo;t. This way you can recommend things they definitely <em>have not seen</em>.</li> +<li>A simple web crawler where you want to avoid visiting the same pages again and again. You will 100% recognize if the crawler has not seen a particular page, with a possibility of skipping a few pages due to a false positive.</li> +<li>Mapping tags/keywords to large data files/database where you might want to avoid a possibly expensive search if the keyword does not match the contents.</li> +<li>Any case where you want a set which should not be enumerable. For example, when storing privacy sensitive data, using the approach mentioned above doesn&rsquo;t anyone allow to figure out which specific elements are in the set, as there are many possibilities for each slot.</li> +</ul> +<h2 id="bloom-filter">Bloom filter</h2> +<p>In our previous example, the probability of a collision (two elements sharing the same hash) is both very high, and using such a simple hash function yields predictable collisions, which is something we&rsquo;d want to avoid. The reason is, the number of collisions could be very high for a certain set of items, while being low for a different set, leading to uneven distribution of false positives among the set of possible sets of items.</p> +<p>First, it is important to note that the above shown hash function is not a good example of a hash function. I won&rsquo;t go into the details of constructing a hash function in this article, as it&rsquo;s a rather involved topic and I can&rsquo;t really think of any cases where you&rsquo;d need to come up with your own. For now, let&rsquo;s simply consider we have three different hash functions called <code>h1</code>, <code>h2</code> and <code>h3</code>.</p> +<p>To create a bloom filter, we simply need a bit vector and <code>k</code> different hash functions, and use them to calculate multiple bit indexes for each element. That way if two elements have a collision using one hash function, they don&rsquo;t necessarily have a collision with the other ones, as each of the hash functions is different and returns a different index.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// Here we assume that `bitvector` is an N-bit long bit vector. See references at the end of this +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// article if you&#39;re unsure on how it works. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">function</span> insert<span style="color:#eceff4">(</span>bitvector<span style="color:#eceff4">,</span> value<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// We simply set all the relevant bits to `1` +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> bitvector<span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span>h1<span style="color:#eceff4">(</span>value<span style="color:#eceff4">),</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> bitvector<span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span>h2<span style="color:#eceff4">(</span>value<span style="color:#eceff4">),</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> bitvector<span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span>h3<span style="color:#eceff4">(</span>value<span style="color:#eceff4">),</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> isMember<span style="color:#eceff4">(</span>bitvector<span style="color:#eceff4">,</span> value<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> bit1 <span style="color:#81a1c1">=</span> bitvector<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span>h1<span style="color:#eceff4">(</span>value<span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> bit2 <span style="color:#81a1c1">=</span> bitvector<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span>h2<span style="color:#eceff4">(</span>value<span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> bit3 <span style="color:#81a1c1">=</span> bitvector<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span>h3<span style="color:#eceff4">(</span>value<span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// An element is in the set only if all of the relevant bits are `1` +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">return</span> bit1 <span style="color:#81a1c1">&amp;&amp;</span> bit2 <span style="color:#81a1c1">&amp;&amp;</span> bit3<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>Now the question is, does having multiple hash functions reduce the probability of a false positive? Sure the probability that three hash functions collide all at once is lower than the probability of just one hash function colliding, but we&rsquo;re also setting three times as many bits.</p> +<p><em>If you&rsquo;re not interested in the math behind calculating the probabilites of collisions, feel free to skip to the next section for a high level overview.</em></p> +<p>If we have a bit vector with <code>N</code> bits, the probability that a hash function selects a specific bit is \(\frac{1}{N}\). This means, that if we do a single insert with a single hash function, the probability that a specific bit is kept at <code>0</code> is \(1 - \frac{1}{N}\). If we use <code>k</code> different hash functions, a single bit is kept at <code>0</code> if none of the hash functions choose it, which means the above test has to pass for all of them, which means the probability is \((1 - \frac{1}{N})^k\).</p> +<p>If we start inserting multiple elements, the probability that a particular bit is <code>0</code> after <code>n</code> elements have been inserted is again calculated by looking at this as passing the above test for each of the inserted elements (done <code>n</code> times), so the probability is \(((1 - \frac{1}{N})^k)^n = (1 - \frac{1}{N})^{kn}\).</p> +<p>The complement of this is \(1 - (1 - \frac{1}{N})^{kn}\), which is the probability that a specific bit is <code>1</code> after having inserted <code>n</code> elements. We get a false positive if and only if all of the hash functions select indexes which are all <code>1</code>, which means the above test needs to pass for all of them, giving us the final probability:</p> +<p>\((1 - (1 - \frac{1}{N})^{kn})^k \approx (1 - e^{-\frac{kn}{N}})^k\)</p> +<p>Using a bit of analysis, we can find that the minimum is at \(\frac{kn}{N} = \ln 2\), which gives us a useful relationship \(k = \ln 2 \cdot \frac{N}{n}\).</p> +<h2 id="choosing-the-right-constants-and-hash-functions">Choosing the right constants and hash functions</h2> +<p>When we want to use a Bloom filter, we don&rsquo;t really start from the number of hash functions. We care about the probability of false positives and how many items we are approximately going to store in the filter. If we know those, it&rsquo;s rather simple <a href="https://stackoverflow.com/questions/658439/how-many-hash-functions-does-my-bloom-filter-need">to calculate the number of bits and hash functions needed</a>. There is actually a nice <a href="https://krisives.github.io/bloom-calculator/">Bloom filter calculator</a> which does exactly this, you put in a number of expected elements, your target probability for false positives, and the calculator will tell you the optimal number of hash functions, and how many bits the backing bit vector should have. I really recommend trying it out with a few different settings for <code>p</code> and <code>n</code> and see how the size of the Bloom filter changes to get a feel for how much memory you might need if you used one.</p> +<p>Now all that is left to do is figure out where to get those <code>k</code> different hash functions. A simple solution suggested by <a href="http://citeseer.ist.psu.edu/viewdoc/download;jsessionid=4060353E67A356EF9528D2C57C064F5A?doi=10.1.1.152.579&amp;rep=rep1&amp;type=pdf">this paper</a> suggests how to create <code>k</code> hash functions from just two different ones (let&rsquo;s call them <code>f</code> and <code>g</code>). We calculate the <code>i</code>-th hash as <code>h(i) = (f(x) + i * g(x)) % N</code> where <code>N</code> is the number of bits in our bit vector.</p> +<p>An important point to note here is that we only need the hash function to be uniform, we don&rsquo;t need a cryptographically secure hash function such as SHA-2. We can use a simpler and faster hash function, such as FNV (<a href="https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function">here</a> and <a href="http://isthe.com/chongo/tech/comp/fnv/">here</a>), which simply does a few bitwise operations and multiplications. There are actually two variants, FNV-1 and FNV-1a, which are almost the same, except for the order of one particular operation. This means we can use these two hash functions as a basis for the trick mentioned above. You can take a look at the <a href="https://github.com/jasondavies/bloomfilter.js/blob/master/bloomfilter.js">bloomfilter.js library</a> which has an efficient implementation of both the Bloom filter, and of both variants of the FNV hash function.</p> +<h2 id="references">References</h2> +<ul> +<li><a href="http://willwhim.wpengine.com/2011/09/03/producing-n-hash-functions-by-hashing-only-once/">Producting n hash functions by hashing only once</a></li> +<li><a href="http://citeseer.ist.psu.edu/viewdoc/download;jsessionid=4060353E67A356EF9528D2C57C064F5A?doi=10.1.1.152.579&amp;rep=rep1&amp;type=pdf">Building a Better Bloom Filter</a></li> +<li><a href="http://isthe.com/chongo/tech/comp/fnv/">FNV hash function</a></li> +<li><a href="https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function">FNV on Wikipedia</a></li> +<li><a href="https://github.com/jasondavies/bloomfilter.js">bloomfilter.js</a></li> +<li><a href="https://projecteuclid.org/DPubS?service=UI&amp;version=1.0&amp;verb=Display&amp;handle=euclid.im/1109191032">Network Applications of Bloom Filters: A Survey</a></li> +<li><a href="https://en.wikipedia.org/wiki/Bloom_filter">Wikipedia article on Bloom filters</a></li> +<li><a href="https://krisives.github.io/bloom-calculator/">Bloom Filter Calculator</a></li> +<li><a href="https://stackoverflow.com/questions/658439/how-many-hash-functions-does-my-bloom-filter-need">Calculating the number of hash functions and bits on StackOverflow</a></li> +</ul> + + + + + Bit Vector in JavaScript + https://blog.jakuba.net/2018-01-09-bit-vector-in-javascript/ + Wed, 17 Jan 2018 10:00:00 +0100 + + https://blog.jakuba.net/2018-01-09-bit-vector-in-javascript/ + <!-- raw HTML omitted --> +<p>A bit vector (also known as bit set or bit array) is a set data structure which uses only 1 bit per element. It answers the question <em>is X in the set?</em>.</p> +<p>The main advantage is memory efficiency and speed, as the memory is allocated in a single continuous block, making it very cache friendly (unlike some tree based data structures), and requiring only a few bitwise operations to access/modify elements in the set. The disadvantage is that we need to know the size of the bit vector beforehand, and that we might be wasting some of the memory if we only store a few elements in a large vector. Let&rsquo;s look at this more closely.</p> +<p>For simplicity, we can think of the bit vector as an array of bits. Not boolean true/false values, or bytes, but <em>bits</em>. Our goal is to map the set of all possible values we might want to store (also called the domain) to a unique index in the bit vector. A good example would be if we wanted a set of small integers (say for an algorithm like the prime sieve of Eratosthenes). We would then need as many bits as is the highest integer we might want to store. If the highest number is 1024, our vector would need 1024 bits, or 128 bytes to store all our membership values (flags).</p> +<p><em>As a small sidenote, you can use the Chrome developer console to run the example code. It was written in a way that you can copy paste each snippet as you go along and everything will work.</em></p> +<h2 id="implementation-using-basic-array-and-number-types">Implementation using basic <code>Array</code> and <code>Number</code> types</h2> +<p>Let&rsquo;s do a simple implementation first, using bare JavaScript arrays of <code>Number</code>. We can do this because the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators">JavaScript bitwise operators treat their operands as 32 bit integers</a>. Afterwards, we&rsquo;ll do the same using the new <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array"><code>Uint32Array</code> type</a>. But first, let&rsquo;s use a regular <code>Array</code> to make things simpler.</p> +<p>To create a bit vector, we first need to specify the number of bits we need (which is also the number of possible values we can store membership of). The question becomes, how many 32-bit integers do we need to store <code>N</code> bits? The answer is unsurprisingly <code>N / 32</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// A function which takes a number of bits and returns an initialized +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// bit vector of given length. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">function</span> buildVector<span style="color:#eceff4">(</span>bitCount<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// The number of bits each `Number` can store. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">var</span> BITS_PER_ELEMENT <span style="color:#81a1c1">=</span> <span style="color:#b48ead">32</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Total number of `Number` values in the vector. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// We round up, because even if we need less than 32 bits, we need at least 1 `Number`. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">var</span> elementCount <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>ceil<span style="color:#eceff4">(</span>bitCount <span style="color:#81a1c1">/</span> BITS_PER_ELEMENT<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> vector <span style="color:#81a1c1">=</span> <span style="color:#81a1c1;font-weight:bold">new</span> <span style="color:#81a1c1">Array</span><span style="color:#eceff4">(</span>elementCount<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// We initialize our bit vector to all zeros +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">for</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">var</span> i <span style="color:#81a1c1">=</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">;</span> i <span style="color:#81a1c1">&lt;</span> elementCount<span style="color:#eceff4">;</span> i<span style="color:#81a1c1">++</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> vector<span style="color:#eceff4">[</span>i<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> vector<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>Now that we have our bit vector, all that is left to do is write the <code>get</code> and <code>set</code> methods for manipulating bit values by their respective bit index. We&rsquo;ll first consider only having a single <code>Number</code> representing 32 bits.</p> +<h2 id="short-introduction-to-binary">Short introduction to binary</h2> +<p>Binary numbers are represented as a sum of powers of two, for example:</p> +<ul> +<li>\(1 = 2^0\)</li> +<li>\(2 = 2^1\)</li> +<li>\(3 = 1 + 2 = 2^0 + 2^1\)</li> +<li>\(4 = 2^2\)</li> +<li>&hellip;</li> +</ul> +<p>If you don&rsquo;t have much experience with binary, you might be tempted to think that \(4 = 1 + 3 = 2^0 + (2^0 + 2^1)\), but that wouldn&rsquo;t work, as we only want one of each power of two. A simple rule to achieve this is that we do a greedy approach, starting from the biggest power of two we can.</p> +<ul> +<li>7 &hellip; we can fit a 4 into that, which means it&rsquo;s \(4 + 3\), and we have to convert the 3, which is \(2 + 1\), resulting in \(4 + 2 + 1\) or \(2^2 + 2^1 + 2^0\)</li> +<li>14 &hellip; we can fit an 8, leaving us with 6, on which we iterate the same rule and get \(4 + 2\), resulting in \(8 + 4 + 2\) or \(2^3 + 2^2 + 2^1\)</li> +</ul> +<p>A binary number is then simply a sequence of 0 or 1, stating 1 for each power of 2 we have (going from the lowest from the right), and 0 for each one we don&rsquo;t have, thus:</p> +<ul> +<li>\(7 = 2^2 + 2^1 + 2^0\) which we can write as \(1 \cdot 2^2 + 1 \cdot 2^1 + 1 \cdot 2^0\), which gives us \(111\)</li> +<li>\(14 = 2^3 + 2^2 + 2^1\) which we can write as \(1 \cdot 2^3 + 1 \cdot 2^2 + 1 \cdot 2^1 + 0 \cdot 2^0\), which gives us \(1110\) reading from the right</li> +</ul> +<p>Note that we can add any number of zeros to the left, so 111 is equivalent to 0111 and 000000111.</p> +<p>A small sidestep here, we can also use hexadecimal numbers to represent binary, as the conversion is rather simple. A hexadecimal digit represents a value from 0 to 15, which is exactly what 4 bits represent. We can thus take any binary number, such as 100000101011111010 and convert it to hex (or back):</p> +<ul> +<li>look at it as groups of 4 bits from the right <code>10 0000 1010 1111 1010</code></li> +<li>add leading zeros to the leftmost group if needed <code>0010 0000 1010 1111 1010</code></li> +<li>convert each individual group <code>2 0 10 15 10</code> to decimal</li> +<li>write each decimal in hex <code>2 0 A F A</code></li> +<li>put them back together, prefixing with <code>0x</code> to get <code>0x20AFA</code></li> +</ul> +<p>Converting hexadecimal back to binary is simple, just take these steps backwards. The reason we use hexadecimal numbers instead of binary often is because they are much easier to visually parse, understand and remember. Looking at a number like <code>0xA1</code> is much clearer than looking at <code>10100001</code>, because you don&rsquo;t have to count how long is each run of zeros/ones.</p> +<h2 id="bitwise-operators">Bitwise operators</h2> +<p>To manipulate individual bits, we&rsquo;ll make use of a few simple bitwise operators. They are called bitwise, because they manipulate individual bits. Specifically, we&rsquo;ll need:</p> +<ul> +<li>negation (NOT), using the <code>~</code> (tilde) operator, which simply flips all the bits</li> +<li>conjunction (AND), using the <code>&amp;</code> operator, which returns 1 when both bits are 1, otherwise 0</li> +<li>disjunction (OR), using the <code>|</code> operator, which returns 0 when both bits are 0, otherwise 1</li> +<li>left shift, using the <code>&lt;&lt;</code> operator, which is shifting all the bits to the left, or semantically multiplying by a given power of 2.</li> +</ul> +<p>Because these operators are bitwise, they will operate on all the bits in parallel. This is different from the more common logical operators <code>&amp;&amp;</code> and <code>||</code> (note that they&rsquo;re doubled), which operate on the whole numbers. Here are a few examples (the <code>b</code> suffix signifies a binary string, this is not proper JavaScript syntax and only used for demonstration purposes):</p> +<ul> +<li><code>1 | 2 = 01b | 10b = 11b = 3</code></li> +<li><code>1 || 2 = 1</code>, because both are converted to booleans, and both are true</li> +<li><code>1 &amp; 3 = 01b &amp; 11b = 01b = 2</code></li> +<li><code>1 &amp;&amp; 3 = 1</code>, because both are converted to booleans, and both are true</li> +<li><code>1 &lt;&lt; 1 = 1b &lt;&lt; 1 = 10b = 2</code>, or \(1 \cdot 2^1\)</li> +<li><code>1 &lt;&lt; 3 = 1b &lt;&lt; 3 = 1000b = 8</code>, or \(1 \cdot 2^3\)</li> +</ul> +<p>To understand the NOT operator, we first need to understand that while mathematically, binary numbers are infinite (or can be), we are only working with 32-bit integers. This means if we start with <code>0</code> and do a negation <code>~0</code>, we get a 32 bit number with all bits set to 1.</p> +<p>Because JavaScript uses two&rsquo;s complement, <code>~0</code> will actually be <code>-1</code> (or <code>11111111111111111111111111111111</code> in binary). This is because the <code>Number</code> type behaves as a <em>signed</em> 32-bit number, which means it also has to represent negative values. The important thing here is that two&rsquo;s complement doesn&rsquo;t say anything about the actual bits, it only specifies what value those bits represent when doing other mathematical operations (<code>+</code>, <code>-</code>, <code>*</code>, etc.). It also affects how the browser will display each number. If you want to learn more about two&rsquo;s complement, check out <a href="https://en.wikipedia.org/wiki/Two%27s_complement">the wikipedia article</a> +or the <a href="http://www.convertforfree.com/twos-complement-calculator/">following online calculator</a> (there are many others) to get an idea for how it works.</p> +<p>But since our bit vector doesn&rsquo;t need to do arithmetic, we don&rsquo;t really need to worry about this. We might occasionally want to print out a given number in hex or binary, which can be done using the <code>.toString</code> function, for example <code>(14).toString(2)</code> outputs binary <code>1110</code> and <code>(14).toString(16)</code> outputs hex <code>e</code>.</p> +<p>Knowing how binary and bitwise operators work, we can finally figure out how to set a specific bit in a given 32-bit integer. The <code>OR</code> operator <code>|</code> is perfect for this, as it won&rsquo;t change a <code>1</code> to <code>0</code> (and thus leaving the existing values alone), but will be able to set a <code>0</code> to <code>1</code>. Counting from 0, if we want to set the 1st bit (at index 0) to <code>1</code>, we simply do <code>num | 1</code>, as this can also be read as <code>num | 00000000000000000000000000000001b</code>. If we wanted to set the 2nd bit (at index 1), we&rsquo;d want <code>num | 10b</code>, or <code>num | 2</code> in decimal/hex. The 3rd bit (at index 2) would be <code>num | 100b</code> or <code>num | 4</code>, the 4th bit (at index 3) would be <code>num | 1000b</code> or <code>num | 8</code>, and so on. We&rsquo;ll call the number on the right side of the operator a <em>bit mask</em>.</p> +<p>If you look closely, you can probably figure out the pattern. To set the <code>i</code>-th bit, we need to OR the number with \(2^i\), which can be easily created with a left shift as <code>1 &lt;&lt; i</code>. The whole operation then becomes <code>num | (1 &lt;&lt; i)</code>. Before moving on, let&rsquo;s do a more visual example. We&rsquo;ll start with <code>num = 0xDA</code> (or <code>11011010</code>, or <code>218</code> dec), and toggle the 3rd bit (index 2).</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>num 11011010 +</span></span><span style="display:flex;"><span>mask 00000100 +</span></span><span style="display:flex;"><span>OR | -------- +</span></span><span style="display:flex;"><span> 11011110 +</span></span></code></pre></div><p>We can also use the same operation to check if a given bit is set. As all the bits except for the <code>i</code>-th are zero, we can use the <code>&amp;</code> operator, which will return a non-zero number if and only if the <code>i</code>-th bit in <code>num</code> is 1. The <code>get</code> operation is then <code>num &amp; (1 &lt;&lt; i)</code>.</p> +<p>Lastly, we might want to remove elements from the bit vector, which means we need the ability to clear a specific bit. A small recap of the <code>&amp;</code> operator.</p> +<pre tabindex="0"><code>| &amp; | 0 | 1 | +|---|---|---| +| 0 | 0 | 0 | +| 1 | 0 | 1 | +</code></pre><p>We can see that if we set the mask to all <code>1</code>, doing <code>num &amp; 1111...1111b</code> doesn&rsquo;t change the <code>num</code> value. We also see that no matter what value is in <code>num</code>, if any of the bits in the mask is <code>0</code>, the resulting bit will also be <code>0</code>. Thus <code>num &amp; 11101b</code> will set the 2nd bit from the right (index 1) to <code>0</code> and leave all of the other bits intact.</p> +<p>Constructing such mask is simple, since we only need to take our <code>set</code> mask from before and flip all the bits using the NOT operator <code>~</code>. Resulting in <code>num &amp; (~(1 &lt;&lt; i))</code>. I&rsquo;ve added extra parentheses to make the order of operations clear. Beware that <code>&amp;</code> and <code>|</code> have a very low priority, so it might be a good idea to be very explicit with parens around bit operations unless you&rsquo;re sure what you&rsquo;re doing is correct.</p> +<p>Here&rsquo;s a similar example as we did for OR, starting with <code>num = 0xDA</code>, clearing the 7th bit (index 6). We first construct the mask step by step <code>1 &lt;&lt; 6 = 01000000b</code>, followed by a negation <code>~01000000 = 10111111</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>num 11011010 +</span></span><span style="display:flex;"><span>mask 10111111 +</span></span><span style="display:flex;"><span>AND &amp; -------- +</span></span><span style="display:flex;"><span> 10011010 +</span></span></code></pre></div><h2 id="implementing-get-set-and-clear-on-a-32-bit-vector">Implementing <code>get</code>, <code>set</code> and <code>clear</code> on a 32-bit vector</h2> +<p>As mentioned before, let&rsquo;s first consider only a 32-bit vector stored in a single <code>Number</code>. The operations would be:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// Set the i-th bit to 1 +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">function</span> set<span style="color:#eceff4">(</span>vec<span style="color:#eceff4">,</span> i<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> vec <span style="color:#81a1c1">|</span> <span style="color:#eceff4">(</span><span style="color:#b48ead">1</span> <span style="color:#81a1c1">&lt;&lt;</span> i<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// Clear the i-th bit +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">function</span> clear<span style="color:#eceff4">(</span>vec<span style="color:#eceff4">,</span> i<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> vec <span style="color:#81a1c1">&amp;</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">~</span><span style="color:#eceff4">(</span><span style="color:#b48ead">1</span> <span style="color:#81a1c1">&lt;&lt;</span> i<span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// Return the value of the i-th bit +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">function</span> get<span style="color:#eceff4">(</span>vec<span style="color:#eceff4">,</span> i<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> value <span style="color:#81a1c1">=</span> vec <span style="color:#81a1c1">&amp;</span> <span style="color:#eceff4">(</span><span style="color:#b48ead">1</span> <span style="color:#81a1c1">&lt;&lt;</span> i<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// we convert to boolean to make sure the result is always 0 or 1, +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// instead of what is returned by the mask +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">return</span> value <span style="color:#81a1c1">!=</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>Note that all of these functions return a new number as their result. Let&rsquo;s test to see if it works:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// Since our bit vector is stored in a single number, we simply initialize it as 0. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">var</span> vec <span style="color:#81a1c1">=</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>vec <span style="color:#81a1c1">=</span> set<span style="color:#eceff4">(</span>vec<span style="color:#eceff4">,</span> <span style="color:#b48ead">3</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;is 3 in vec? &#34;</span> <span style="color:#81a1c1">+</span> get<span style="color:#eceff4">(</span>vec<span style="color:#eceff4">,</span> <span style="color:#b48ead">3</span><span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// is 3 in vec? true +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;is 4 in vec? &#34;</span> <span style="color:#81a1c1">+</span> get<span style="color:#eceff4">(</span>vec<span style="color:#eceff4">,</span> <span style="color:#b48ead">4</span><span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// is 4 in vec? false +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span>vec <span style="color:#81a1c1">=</span> clear<span style="color:#eceff4">(</span>vec<span style="color:#eceff4">,</span> <span style="color:#b48ead">3</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;is 3 in vec? &#34;</span> <span style="color:#81a1c1">+</span> get<span style="color:#eceff4">(</span>vec<span style="color:#eceff4">,</span> <span style="color:#b48ead">3</span><span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// is 3 in vec? false +</span></span></span></code></pre></div><p>Remember the number only has 32-bits, so don&rsquo;t use an index bigger than 31. If you do, it will simply wrap around, so you&rsquo;ll get <code>set(0, 0) == set(0, 32)</code>.</p> +<h2 id="implementing-get-set-and-clear-on-an-arbitrary-length-bit-vector">Implementing <code>get</code>, <code>set</code> and <code>clear</code> on an arbitrary length bit vector</h2> +<p>Now we&rsquo;re finally ready to create the whole data structure, an arbitrary length bit vector. We need to modify our <code>get</code>, <code>set</code>, and <code>clear</code> to calculate the right <code>Number</code> within the array first, and then to do the same bit manipulation they did before.</p> +<p>Going again from the right, bits 0 - 31 will be stored in the 1st <code>Number</code> (at index 0), bits 32 - 63 at index 1, 64 - 95 at index 2, etc. From this, we can see that the index in the bigger array is simply the bit index divided by 32 and rounded down. Simply <code>Math.floor(i / 32)</code>. This gives us the index of the <code>Number</code>.</p> +<p>To get the bit index within the number, we simply take the remainder of dividing by 32, or the modulo 32 of the original bit index. This gives us <code>i % 32</code> for the bit index. Putting this together (note that since we&rsquo;re using an <code>Array</code>, the bit vector is now mutable, unlike the previous 32-bit version using only a <code>Number</code>). I&rsquo;ve added the original <code>buildVector</code> function to make it easier to copy paste this code as a whole.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// Set the i-th bit to 1 +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">function</span> set<span style="color:#eceff4">(</span>vec<span style="color:#eceff4">,</span> i<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> bigIndex <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>floor<span style="color:#eceff4">(</span>i <span style="color:#81a1c1">/</span> <span style="color:#b48ead">32</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> smallIndex <span style="color:#81a1c1">=</span> i <span style="color:#81a1c1">%</span> <span style="color:#b48ead">32</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> vec<span style="color:#eceff4">[</span>bigIndex<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> vec<span style="color:#eceff4">[</span>bigIndex<span style="color:#eceff4">]</span> <span style="color:#81a1c1">|</span> <span style="color:#eceff4">(</span><span style="color:#b48ead">1</span> <span style="color:#81a1c1">&lt;&lt;</span> smallIndex<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// Clear the i-th bit +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">function</span> clear<span style="color:#eceff4">(</span>vec<span style="color:#eceff4">,</span> i<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> bigIndex <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>floor<span style="color:#eceff4">(</span>i <span style="color:#81a1c1">/</span> <span style="color:#b48ead">32</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> smallIndex <span style="color:#81a1c1">=</span> i <span style="color:#81a1c1">%</span> <span style="color:#b48ead">32</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> vec<span style="color:#eceff4">[</span>bigIndex<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> vec<span style="color:#eceff4">[</span>bigIndex<span style="color:#eceff4">]</span> <span style="color:#81a1c1">&amp;</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">~</span><span style="color:#eceff4">(</span><span style="color:#b48ead">1</span> <span style="color:#81a1c1">&lt;&lt;</span> smallIndex<span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// Return the value of the i-th bit +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">function</span> get<span style="color:#eceff4">(</span>vec<span style="color:#eceff4">,</span> i<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> bigIndex <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>floor<span style="color:#eceff4">(</span>i <span style="color:#81a1c1">/</span> <span style="color:#b48ead">32</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> smallIndex <span style="color:#81a1c1">=</span> i <span style="color:#81a1c1">%</span> <span style="color:#b48ead">32</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> value <span style="color:#81a1c1">=</span> vec<span style="color:#eceff4">[</span>bigIndex<span style="color:#eceff4">]</span> <span style="color:#81a1c1">&amp;</span> <span style="color:#eceff4">(</span><span style="color:#b48ead">1</span> <span style="color:#81a1c1">&lt;&lt;</span> smallIndex<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// we convert to boolean to make sure the result is always 0 or 1, +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// instead of what is returned by the mask +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">return</span> value <span style="color:#81a1c1">!=</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// A function which takes a number of bits and returns an initialized +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// bit vector of given length. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">function</span> buildVector<span style="color:#eceff4">(</span>bitCount<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// Total number of `Number` values in the vector. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// Adding Math.ceil here to make sure we allocate enough space even if the size +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// is not divisible by 32. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">var</span> elementCount <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>ceil<span style="color:#eceff4">(</span>bitCount <span style="color:#81a1c1">/</span> <span style="color:#b48ead">32</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> vector <span style="color:#81a1c1">=</span> <span style="color:#81a1c1;font-weight:bold">new</span> <span style="color:#81a1c1">Array</span><span style="color:#eceff4">(</span>elementCount<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">for</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">var</span> i <span style="color:#81a1c1">=</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">;</span> i <span style="color:#81a1c1">&lt;</span> elementCount<span style="color:#eceff4">;</span> i<span style="color:#81a1c1">++</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> vector<span style="color:#eceff4">[</span>i<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> vector<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>We can do a similar test as we did before to test our bit vector:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// Since our bit vector is stored in a single number, we simply initialize it as 0. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span><span style="color:#81a1c1;font-weight:bold">var</span> vec <span style="color:#81a1c1">=</span> buildVector<span style="color:#eceff4">(</span><span style="color:#b48ead">64</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>set<span style="color:#eceff4">(</span>vec<span style="color:#eceff4">,</span> <span style="color:#b48ead">30</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;is 30 in vec? &#34;</span> <span style="color:#81a1c1">+</span> get<span style="color:#eceff4">(</span>vec<span style="color:#eceff4">,</span> <span style="color:#b48ead">30</span><span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// is 30 in vec? true +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;is 40 in vec? &#34;</span> <span style="color:#81a1c1">+</span> get<span style="color:#eceff4">(</span>vec<span style="color:#eceff4">,</span> <span style="color:#b48ead">40</span><span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// is 40 in vec? false +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span>clear<span style="color:#eceff4">(</span>vec<span style="color:#eceff4">,</span> <span style="color:#b48ead">30</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;is 30 in vec? &#34;</span> <span style="color:#81a1c1">+</span> get<span style="color:#eceff4">(</span>vec<span style="color:#eceff4">,</span> <span style="color:#b48ead">30</span><span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// is 30 in vec? false +</span></span></span></code></pre></div><h2 id="using-uint32array-instead-of-an-array-of-number">Using Uint32Array instead of an <code>Array</code> of <code>Number</code></h2> +<p>Modern browsers now provide a better and more efficient variant to an <code>Array</code> of <code>Number</code>, which is using <code>Uint32Array</code>. The difference here is that JavaScript <code>Array</code> is not exactly the array you would expect if you came out of a computer science class. It behaves more like a hash map with integer keys. You can also store different types in the same array, for example <code>[1, &quot;hello&quot;]</code> is completely valid JavaScript. Secondly, <code>Number</code> is not a 32-bit integer. <a href="https://tc39.github.io/ecma262/#sec-ecmascript-language-types-number-type">According to the standard</a>, <code>Number</code> is a IEEE-754 double precision float. The trick here is that the bitwise operators convert their operands to a 32-bit integer before applying the operation. The conversion is defined as an abstract operation, so it most likely comes down to how the implementation chooses to handle things.</p> +<p>The ideal scenario would be that the JIT (just in-time compiler) recognizes that we&rsquo;re only doing bitwise operations on something that starts out as a constant zero, and thus uses a 32-bit integer as the backing store for our data, and also recognizes that the array doesn&rsquo;t contain anything else, so it wouldn&rsquo;t have to use a generic implementation that allows different types, but rather a continuous block of memory. While this might be possible, it&rsquo;s most likely not what happens, at least not something that can be guarateed to happen 100% of the time, because the JIT would need to understand everything your code is doing to prove that such optimization is possible. The halting problem however proves that the compiler can&rsquo;t understand any arbitrary code, and as such any optimization could be only based on heuristics.</p> +<p>This is why the <code>Uint32Array</code> type was added to JavaScript. While the compiler/interpreter/JIT can&rsquo;t know that we only intend to use 32-bit integers, we as the programmers do know it, so we can choose a more specific data structure that allows for exactly that. <code>Uint32Array</code> is a type which has only one purpose, to store unsigned 32-bit integers in a continuous block of memory.</p> +<p>Using it is actually even simpler than what we did before, as our <code>buildVector</code> function turns into a one liner.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> buildVector<span style="color:#eceff4">(</span>bitCount<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// The constructor accepts a number of 32-bit integers in the array, +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// which is simply the number of bits in our bit vector divided by 32. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// We also keep the `Math.ceil` just to make the API more robust. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#81a1c1;font-weight:bold">new</span> Uint32Array<span style="color:#eceff4">(</span><span style="color:#81a1c1">Math</span><span style="color:#eceff4">.</span>ceil<span style="color:#eceff4">(</span>bitCount <span style="color:#81a1c1">/</span> <span style="color:#b48ead">32</span><span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>On the outside, the <code>Uint32Array</code> behaves just like an <code>Array</code>, with the exception that the operands to the indexer <code>[]</code> operator get converted to unsigned 32-bit integers.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> arr <span style="color:#81a1c1">=</span> <span style="color:#81a1c1;font-weight:bold">new</span> Uint32Array<span style="color:#eceff4">(</span><span style="color:#b48ead">10</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>arr<span style="color:#eceff4">[</span><span style="color:#b48ead">0</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> <span style="color:#a3be8c">&#34;foo&#34;</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span>arr<span style="color:#eceff4">[</span><span style="color:#b48ead">1</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> <span style="color:#a3be8c">&#34;123&#34;</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span>arr<span style="color:#eceff4">[</span><span style="color:#b48ead">2</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> <span style="color:#b48ead">3.14</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span>arr<span style="color:#eceff4">[</span><span style="color:#b48ead">0</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1">+</span> <span style="color:#a3be8c">&#34; &#34;</span> <span style="color:#81a1c1">+</span> arr<span style="color:#eceff4">[</span><span style="color:#b48ead">1</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1">+</span> <span style="color:#a3be8c">&#34; &#34;</span> <span style="color:#81a1c1">+</span> arr<span style="color:#eceff4">[</span><span style="color:#b48ead">2</span><span style="color:#eceff4">]);</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// 0 123 3 +</span></span></span></code></pre></div><p>Everything else about the bit vector (<code>set</code>, <code>get</code>, and <code>clear</code>) will stay the same, so there isn&rsquo;t really anything we&rsquo;re giving up for using the more efficient <code>Uint32Array</code> version.</p> +<h2 id="conclusion">Conclusion</h2> +<p>If you&rsquo;ve read this far, you should now feel pretty confident about how the bit vector works, and be able to implement it yourself. A bit vector might not be the most popular data structure, but it can come handy in various different scenarios. A specific example could be using binary frames with the <code>WebSocket</code> API, in which case you might want to minimize the network traffic as much as possible. When working with binary frames, you will most certainly run into <code>Uint32Array</code> and bitwise operators, so at least knowing how a bit vector works can help you there. It&rsquo;s also useful to know that there are other built-in array types with predefined length, such as <code>Uint8Array</code>, <code>Int32Array</code> (note the lack of <code>U</code>, as this is a signed integer version of a 32-bit array), <code>Float64Array</code>, etc. For more details on these check out the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects">Indexed collections section under Global Objects on MDN</a>. You might also be interested in seeing <a href="http://kangax.github.io/compat-table/es6/#test-typed_arrays">browser support of typed arrays</a> in the modern browsers and different polyfill options.</p> +<p>Lastly, I&rsquo;d like to note a little bit about dynamically sized bit vectors. Much like a regular array, a bit vector can also be implemented in a way that allows for resizing. In the <code>Array</code> variant, we would just need to push a few additional zeroed <code>Number</code> instances into the array to make the bit vector larger, while the <code>Uint32Array</code> variant would require us to allocate a new <code>Uint32Array</code> with larger size and copy things over. At first it might seem like the <code>Array</code> variant is clearly superior in this regard, but here&rsquo;s a few thoughts:</p> +<ul> +<li>if the JIT recognized our <code>Array</code> should use an efficient packed 32-bit integer block of memory to store the data, pushing a new element into it would do exactly the same as if we create a new <code>Uint32Array</code> (there could be more optimizations going on, but the same could be said for the JIT optimizing a resize of the <code>Uint32Array</code> variant)</li> +<li>if the <code>Array</code> is backed by a generic array of objects with extended capacity for pushing new elements into it, the <code>push</code> itself wouldn&rsquo;t cost as much, but there could be a price paid in terms of performance of the regular <code>set</code>, <code>get</code> and <code>clear</code> operations</li> +</ul> +<p>Note that this is mostly food for thought, I haven&rsquo;t done any benchmarks comparing the two variants, and could be very wrong with regards what happens in actual JavaScript implementations. If I was made to guess, I&rsquo;d say the <code>Uint32Array</code> would outperform the <code>Array</code> even with an occasional resize. But feel free to correct me on this in the comments.</p> +<h2 id="references">References</h2> +<ul> +<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators">MDN Bitwise Operators</a></li> +<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array">MDN Uint32Array</a></li> +<li><a href="https://en.wikipedia.org/wiki/Two%27s_complement">Two&rsquo;s complement on Wikipedia</a></li> +<li><a href="http://www.convertforfree.com/twos-complement-calculator/">Two&rsquo;s complement calculator</a></li> +<li><a href="http://kangax.github.io/compat-table/es6/#test-typed_arrays">Typed Array browser compatibility table</a></li> +<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects">MDN Global Objects (Indexed collections section)</a></li> +<li><a href="http://kangax.github.io/compat-table/es6/#test-typed_arrays">Browser support of typed arrays</a></li> +</ul> + + + + + Visualizing TensorFlow Graphs in Jupyter Notebooks + https://blog.jakuba.net/tensorboard-visualization/ + Tue, 30 May 2017 00:00:00 +0000 + + https://blog.jakuba.net/tensorboard-visualization/ + <!-- raw HTML omitted --> +<p><em>Prerequisites</em>: This article assumes you are familiar with the basics of Python, TensorFlow, and Jupyter notebooks. +We won&rsquo;t use any of the advanced TensorFlow features, as our goal is just to visualize the computation graphs.</p> +<!-- raw HTML omitted --> +<p>TensorFlow operations form a computation graph. And while for small examples +you might be able to look at the code and immediately see what is going on, +larger computation graphs might not be so obvious. Visualizing the graph can help +both in diagnosing issues with the computation itself, but also in understanding +how certain operations in TensorFlow work and how are things put together.</p> +<p>We&rsquo;ll take a look at a few different ways of visualizing TensorFlow graphs, and most importantly, +show how to do it in a very simple and time-efficient way. It shouldn&rsquo;t take more than one or two lines +of code to draw a graph we have already defined. Now onto the specifics, we&rsquo;ll take a look at the following +visualization techniques:</p> +<ul> +<li>Exploring the textual graph definition</li> +<li>Building a GraphViz DOTgraph from that directly in the Jupyter Notebook</li> +<li>Visualizing the same graph in a locally running instance of TensorBoard</li> +<li>Using a self contained snippet that uses a cloud deployed publically available TensorBoard instance to render the graph inline in a Jupyter Notebook.</li> +</ul> +<p>First, let us create a simple TensorFlow graph. Regular operations such as creating a placeholder with <a href="https://www.tensorflow.org/api_docs/python/tf/placeholder">tf.placeholder</a> will create a node in the so called <em>default graph</em>. We can access it via <code>tf.get_default_graph()</code>, but we can also change it temporarily. In our example below, we&rsquo;ll create a new instance of the <a href="https://www.tensorflow.org/api_docs/python/tf/Graph">tf.Graph</a> object and create a simple operation adding two variables</p> +<p>$$c = a + b$$</p> +<p>Note that we&rsquo;re giving explicit names to both of the placeholder variables.</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">import</span> <span style="color:#8fbcbb">tensorflow</span> <span style="color:#81a1c1;font-weight:bold">as</span> <span style="color:#8fbcbb">tf</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>g <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>Graph<span style="color:#eceff4">()</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">with</span> g<span style="color:#81a1c1">.</span>as_default<span style="color:#eceff4">():</span> +</span></span><span style="display:flex;"><span> a <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;a&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> b <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;b&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> c <span style="color:#81a1c1">=</span> a <span style="color:#81a1c1">+</span> b +</span></span></code></pre></div><!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<p>The variable <code>g</code> now contains a definition of the computation graph for the operation $c = a + b$. +We can use the <code>g.as_graph_def()</code> method to get a textual representation of the graph for our expression. +While the main use of this is for serialization and later deserialization via <a href="https://www.tensorflow.org/api_docs/python/tf/import_graph_def">tf.import_graph_def</a>, we&rsquo;ll use it to create a GraphViz DOTgraph.</p> +<p>Let us take a look at the <a href="https://www.tensorflow.org/api_docs/python/tf/GraphDef">GraphDef</a> for our simple +expression. First, we&rsquo;ll inspect the names of all of the nodes in the graph.</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#eceff4">[</span>node<span style="color:#81a1c1">.</span>name <span style="color:#81a1c1;font-weight:bold">for</span> node <span style="color:#81a1c1;font-weight:bold">in</span> g<span style="color:#81a1c1">.</span>as_graph_def<span style="color:#eceff4">()</span><span style="color:#81a1c1">.</span>node<span style="color:#eceff4">]</span> +</span></span></code></pre></div><!-- raw HTML omitted --> +<pre><code>['a', 'b', 'add'] +</code></pre> +<!-- raw HTML omitted --> +<p>As expected, there are three nodes in the Graph. One for each of our variables, and one for the addition +opeartion. The placeholder variable nodes have a name since we explicitely named them when calling <code>tf.placeholder</code>. If we omit the <code>name</code> keyword argument, TensorFlow will simply generate a name on its own, as it did with the add operation.</p> +<p>Next, we can take a look at the edges in the graph. Each GraphDef node has an <code>input</code> field which specifies +of the nodes where it has edges. Let&rsquo;s take a look:</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>g<span style="color:#81a1c1">.</span>as_graph_def<span style="color:#eceff4">()</span><span style="color:#81a1c1">.</span>node<span style="color:#eceff4">[</span><span style="color:#b48ead">2</span><span style="color:#eceff4">]</span><span style="color:#81a1c1">.</span>input +</span></span></code></pre></div><!-- raw HTML omitted --> +<pre><code>['a', 'b'] +</code></pre> +<!-- raw HTML omitted --> +<p>As we can see, there are two edges, one to each variable. We can feed this directly into GraphViz.</p> +<!-- raw HTML omitted --> +<h2 id="building-a-graphviz-dotgraph">Building a GraphViz DOTgraph</h2> +<!-- raw HTML omitted --> +<p><a href="http://www.graphviz.org/">GraphViz</a> is a fairly popular library for drawing graphs, trees and other graph-shaped data structures. We&rsquo;ll use the <a href="https://pypi.python.org/pypi/graphviz/0.7.1">Python GraphViz package</a> which provides a nice +clean interface. We can install it directly inside a Jupyter notebook via <code>!pip install graphviz</code>.</p> +<p>The graph definition itself will be rather simple, and we&rsquo;ll take inspiration from a similar piece of code in +TensorFlow itself (in <a href="https://github.com/tensorflow/tensorflow/blob/master/tensorflow/tools/quantization/graph_to_dot.py">graph_to_dot.py</a>) which generates a DOTgraph file format for a given GraphDef. Unfortunately it is only available as a command line script, and as such we can&rsquo;t call it directly from our code. This is why we&rsquo;ll be implementing it ourselves, but don&rsquo;t worry, it will only +be a few lines of code.</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">from</span> <span style="color:#8fbcbb">graphviz</span> <span style="color:#81a1c1;font-weight:bold">import</span> Digraph +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>dot <span style="color:#81a1c1">=</span> Digraph<span style="color:#eceff4">()</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">for</span> n <span style="color:#81a1c1;font-weight:bold">in</span> g<span style="color:#81a1c1">.</span>as_graph_def<span style="color:#eceff4">()</span><span style="color:#81a1c1">.</span>node<span style="color:#eceff4">:</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic"># Each node has a name and a label. The name identifies the node</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic"># while the label is what will be displayed in the graph.</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic"># We&#39;re using the name as a label for simplicity.</span> +</span></span><span style="display:flex;"><span> dot<span style="color:#81a1c1">.</span>node<span style="color:#eceff4">(</span>n<span style="color:#81a1c1">.</span>name<span style="color:#eceff4">,</span> label<span style="color:#81a1c1">=</span>n<span style="color:#81a1c1">.</span>name<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">for</span> i <span style="color:#81a1c1;font-weight:bold">in</span> n<span style="color:#81a1c1">.</span>input<span style="color:#eceff4">:</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic"># Edges are determined by the names of the nodes</span> +</span></span><span style="display:flex;"><span> dot<span style="color:#81a1c1">.</span>edge<span style="color:#eceff4">(</span>i<span style="color:#eceff4">,</span> n<span style="color:#81a1c1">.</span>name<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"># Jupyter can automatically display the DOT graph,</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"># which allows us to just return it as a value.</span> +</span></span><span style="display:flex;"><span>dot +</span></span></code></pre></div><!-- raw HTML omitted --> +<p><img src="./index_10_0.svg" alt="svg"></p> +<!-- raw HTML omitted --> +<p>Now let&rsquo;s wrap this in a function and try using it on a more complicated expression.</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">def</span> <span style="color:#88c0d0">tf_to_dot</span><span style="color:#eceff4">(</span>graph<span style="color:#eceff4">):</span> +</span></span><span style="display:flex;"><span> dot <span style="color:#81a1c1">=</span> Digraph<span style="color:#eceff4">()</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">for</span> n <span style="color:#81a1c1;font-weight:bold">in</span> g<span style="color:#81a1c1">.</span>as_graph_def<span style="color:#eceff4">()</span><span style="color:#81a1c1">.</span>node<span style="color:#eceff4">:</span> +</span></span><span style="display:flex;"><span> dot<span style="color:#81a1c1">.</span>node<span style="color:#eceff4">(</span>n<span style="color:#81a1c1">.</span>name<span style="color:#eceff4">,</span> label<span style="color:#81a1c1">=</span>n<span style="color:#81a1c1">.</span>name<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">for</span> i <span style="color:#81a1c1;font-weight:bold">in</span> n<span style="color:#81a1c1">.</span>input<span style="color:#eceff4">:</span> +</span></span><span style="display:flex;"><span> dot<span style="color:#81a1c1">.</span>edge<span style="color:#eceff4">(</span>i<span style="color:#eceff4">,</span> n<span style="color:#81a1c1">.</span>name<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> dot +</span></span></code></pre></div><!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<p>We&rsquo;ll build another graph calculating the area of a circle with the formula $\pi * r^2$. +As we can see TensorFlow does what we would actually expect and links the same placeholder +to two multiplication operations.</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>g <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>Graph<span style="color:#eceff4">()</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">with</span> g<span style="color:#81a1c1">.</span>as_default<span style="color:#eceff4">():</span> +</span></span><span style="display:flex;"><span> pi <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>constant<span style="color:#eceff4">(</span><span style="color:#b48ead">3.14</span><span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;pi&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> r <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;r&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> y <span style="color:#81a1c1">=</span> pi <span style="color:#81a1c1">*</span> r <span style="color:#81a1c1">*</span> r +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>tf_to_dot<span style="color:#eceff4">(</span>g<span style="color:#eceff4">)</span> +</span></span></code></pre></div><!-- raw HTML omitted --> +<p><img src="./index_14_0.svg" alt="svg"></p> +<!-- raw HTML omitted --> +<h2 id="using-a-local-tensorboard-instance-to-visualize-the-graph">Using a local TensorBoard instance to visualize the graph</h2> +<!-- raw HTML omitted --> +<p>While GraphViz might be nice for visualizing small graphs, neural networks can grow to quite a large size. +TensorBoard allows us to easily group parts of our equations into <em>scopes</em>, which will then be visually +separated in the resulting graph. But before doing this, let&rsquo;s just try visualizing our previous graph +with TensorBoard.</p> +<p>All we need to do is save it using the <a href="https://www.tensorflow.org/api_docs/python/tf/summary/FileWriter">tf.summary.FileWriter</a>, which takes a directory and a graph, and serializes +the graph in a format that TensorBoard can read. The directory can be anything you&rsquo;d like, just make sure you point to the same directory using the <code>tensorboard --logdir=DIR</code> command (<code>DIR</code> being the directory you specified to the <code>FileWriter</code>).</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"># We write the graph out to the `logs` directory</span> +</span></span><span style="display:flex;"><span>tf<span style="color:#81a1c1">.</span>summary<span style="color:#81a1c1">.</span>FileWriter<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;logs&#34;</span><span style="color:#eceff4">,</span> g<span style="color:#eceff4">)</span><span style="color:#81a1c1">.</span>close<span style="color:#eceff4">()</span> +</span></span></code></pre></div><!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<p>Next, open up a console and navigate to the same directory from which you executed the <code>FileWriter</code> command, and run <code>tensorboard --logdir=logs</code>. This will launch an instance of TensorBoard which you can access at <a href="http://localhost:6006">http://localhost:6006</a>. Then navigate to the <code>Graphs</code> section and you should see a graph that looks like the following image. Note that you can also click on the nodes in the graph to inspect them further.</p> +<!-- raw HTML omitted --> +<p><img src="http://i.imgur.com/XajS4Tv.png" alt="tensorboard graph"></p> +<!-- raw HTML omitted --> +<p>Now this is all nice and interactive, but we can already see some things which make it harder to read. For example, when we type $\pi * r^2$ we generally don&rsquo;t think of the $r^2$ as a multiplication operation (even though we implement it as such), we think of it as a <em>square</em> operation. This becomes more visible when the graph contains a lot more +operations.</p> +<p>Luckily, TensorFlow allows us to bundle operations together into a single unit called <em>scope</em>. But first, lets take a look at a more complicated example without using scopes. We&rsquo;ll create a very simple feed forward neural network with three layers (with respective weights $W_1, W_2, W_3$ and biases $b_1, b_2, b_3$).</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>g <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>Graph<span style="color:#eceff4">()</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">with</span> g<span style="color:#81a1c1">.</span>as_default<span style="color:#eceff4">():</span> +</span></span><span style="display:flex;"><span> X <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;X&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> W1 <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;W1&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> b1 <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;b1&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> a1 <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>nn<span style="color:#81a1c1">.</span>relu<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>matmul<span style="color:#eceff4">(</span>X<span style="color:#eceff4">,</span> W1<span style="color:#eceff4">)</span> <span style="color:#81a1c1">+</span> b1<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> W2 <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;W2&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> b2 <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;b2&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> a2 <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>nn<span style="color:#81a1c1">.</span>relu<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>matmul<span style="color:#eceff4">(</span>a1<span style="color:#eceff4">,</span> W2<span style="color:#eceff4">)</span> <span style="color:#81a1c1">+</span> b2<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> W3 <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;W3&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> b3 <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;b3&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> y_hat <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>matmul<span style="color:#eceff4">(</span>a2<span style="color:#eceff4">,</span> W3<span style="color:#eceff4">)</span> <span style="color:#81a1c1">+</span> b3 +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>tf<span style="color:#81a1c1">.</span>summary<span style="color:#81a1c1">.</span>FileWriter<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;logs&#34;</span><span style="color:#eceff4">,</span> g<span style="color:#eceff4">)</span><span style="color:#81a1c1">.</span>close<span style="color:#eceff4">()</span> +</span></span></code></pre></div><!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<p>Looking at the result in TensorBoard, the result is pretty much what we would expect. The only problem is, TensorBoard displays it as a single expression. It isn&rsquo;t immediately apparent that we meant to think about our code in terms of layers.</p> +<!-- raw HTML omitted --> +<p><img src="http://i.imgur.com/pwcEAgb.png" alt="simple feedforward neural network without scopes"></p> +<!-- raw HTML omitted --> +<p>We can improve this by using the above-mentioned <a href="https://www.tensorflow.org/api_docs/python/tf/name_scope">tf.name_scope</a> +function. Let us rewrite our feedforward network code to separate each layer into its own scope.</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>g <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>Graph<span style="color:#eceff4">()</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">with</span> g<span style="color:#81a1c1">.</span>as_default<span style="color:#eceff4">():</span> +</span></span><span style="display:flex;"><span> X <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;X&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">with</span> tf<span style="color:#81a1c1">.</span>name_scope<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;Layer1&#34;</span><span style="color:#eceff4">):</span> +</span></span><span style="display:flex;"><span> W1 <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;W1&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> b1 <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;b1&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> a1 <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>nn<span style="color:#81a1c1">.</span>relu<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>matmul<span style="color:#eceff4">(</span>X<span style="color:#eceff4">,</span> W1<span style="color:#eceff4">)</span> <span style="color:#81a1c1">+</span> b1<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">with</span> tf<span style="color:#81a1c1">.</span>name_scope<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;Layer2&#34;</span><span style="color:#eceff4">):</span> +</span></span><span style="display:flex;"><span> W2 <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;W2&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> b2 <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;b2&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> a2 <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>nn<span style="color:#81a1c1">.</span>relu<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>matmul<span style="color:#eceff4">(</span>a1<span style="color:#eceff4">,</span> W2<span style="color:#eceff4">)</span> <span style="color:#81a1c1">+</span> b2<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">with</span> tf<span style="color:#81a1c1">.</span>name_scope<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;Layer3&#34;</span><span style="color:#eceff4">):</span> +</span></span><span style="display:flex;"><span> W3 <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;W3&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> b3 <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>placeholder<span style="color:#eceff4">(</span>tf<span style="color:#81a1c1">.</span>float32<span style="color:#eceff4">,</span> name<span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;b3&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> y_hat <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>matmul<span style="color:#eceff4">(</span>a2<span style="color:#eceff4">,</span> W3<span style="color:#eceff4">)</span> <span style="color:#81a1c1">+</span> b3 +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>tf<span style="color:#81a1c1">.</span>summary<span style="color:#81a1c1">.</span>FileWriter<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;logs&#34;</span><span style="color:#eceff4">,</span> g<span style="color:#eceff4">)</span><span style="color:#81a1c1">.</span>close<span style="color:#eceff4">()</span> +</span></span></code></pre></div><!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<p>And here&rsquo;s how the resulting graph looks like, showing both a compact view of the whole network (left) and what it looks like when you expand one of the nodes (right).</p> +<!-- raw HTML omitted --> +<p><img src="http://i.imgur.com/6HIpspV.png" alt="simple feedforward network with scopes"></p> +<!-- raw HTML omitted --> +<h2 id="using-a-cloud-hosted-tensorboard-instance-to-do-the-rendering">Using a cloud-hosted TensorBoard instance to do the rendering</h2> +<!-- raw HTML omitted --> +<p>We&rsquo;ll use the modified snippet from the <a href="https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/deepdream/deepdream.ipynb">DeepDream notebook</a> +taken from <a href="https://stackoverflow.com/a/41463991/72583">this StackOverflow answer</a>. It basically takes the <code>tf.GraphDef</code>, +sends it over to the cloud, and embeds an <code>&lt;iframe&gt;</code> with the resulting visualization right in the Jupyter notebook.</p> +<p>Here&rsquo;s the snippet in its whole. All you need to do is call <code>show_graph()</code> and it will handle everything, as shown in the +example below on our previous graph <code>g</code>. The obvious advantage of this approach is that you don&rsquo;t need to run TensorBoard +to visualize the data, but you also need internet access.</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"># TensorFlow Graph visualizer code</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">import</span> <span style="color:#8fbcbb">numpy</span> <span style="color:#81a1c1;font-weight:bold">as</span> <span style="color:#8fbcbb">np</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">from</span> <span style="color:#8fbcbb">IPython.display</span> <span style="color:#81a1c1;font-weight:bold">import</span> clear_output<span style="color:#eceff4">,</span> Image<span style="color:#eceff4">,</span> display<span style="color:#eceff4">,</span> HTML +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">def</span> <span style="color:#88c0d0">strip_consts</span><span style="color:#eceff4">(</span>graph_def<span style="color:#eceff4">,</span> max_const_size<span style="color:#81a1c1">=</span><span style="color:#b48ead">32</span><span style="color:#eceff4">):</span> +</span></span><span style="display:flex;"><span> <span style="color:#a3be8c">&#34;&#34;&#34;Strip large constant values from graph_def.&#34;&#34;&#34;</span> +</span></span><span style="display:flex;"><span> strip_def <span style="color:#81a1c1">=</span> tf<span style="color:#81a1c1">.</span>GraphDef<span style="color:#eceff4">()</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">for</span> n0 <span style="color:#81a1c1;font-weight:bold">in</span> graph_def<span style="color:#81a1c1">.</span>node<span style="color:#eceff4">:</span> +</span></span><span style="display:flex;"><span> n <span style="color:#81a1c1">=</span> strip_def<span style="color:#81a1c1">.</span>node<span style="color:#81a1c1">.</span>add<span style="color:#eceff4">()</span> +</span></span><span style="display:flex;"><span> n<span style="color:#81a1c1">.</span>MergeFrom<span style="color:#eceff4">(</span>n0<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> n<span style="color:#81a1c1">.</span>op <span style="color:#81a1c1">==</span> <span style="color:#a3be8c">&#39;Const&#39;</span><span style="color:#eceff4">:</span> +</span></span><span style="display:flex;"><span> tensor <span style="color:#81a1c1">=</span> n<span style="color:#81a1c1">.</span>attr<span style="color:#eceff4">[</span><span style="color:#a3be8c">&#39;value&#39;</span><span style="color:#eceff4">]</span><span style="color:#81a1c1">.</span>tensor +</span></span><span style="display:flex;"><span> size <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">len</span><span style="color:#eceff4">(</span>tensor<span style="color:#81a1c1">.</span>tensor_content<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> size <span style="color:#81a1c1">&gt;</span> max_const_size<span style="color:#eceff4">:</span> +</span></span><span style="display:flex;"><span> tensor<span style="color:#81a1c1">.</span>tensor_content <span style="color:#81a1c1">=</span> <span style="color:#a3be8c">&#34;&lt;stripped </span><span style="color:#a3be8c">%d</span><span style="color:#a3be8c"> bytes&gt;&#34;</span><span style="color:#81a1c1">%</span>size +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> strip_def +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">def</span> <span style="color:#88c0d0">show_graph</span><span style="color:#eceff4">(</span>graph_def<span style="color:#eceff4">,</span> max_const_size<span style="color:#81a1c1">=</span><span style="color:#b48ead">32</span><span style="color:#eceff4">):</span> +</span></span><span style="display:flex;"><span> <span style="color:#a3be8c">&#34;&#34;&#34;Visualize TensorFlow graph.&#34;&#34;&#34;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#81a1c1">hasattr</span><span style="color:#eceff4">(</span>graph_def<span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#39;as_graph_def&#39;</span><span style="color:#eceff4">):</span> +</span></span><span style="display:flex;"><span> graph_def <span style="color:#81a1c1">=</span> graph_def<span style="color:#81a1c1">.</span>as_graph_def<span style="color:#eceff4">()</span> +</span></span><span style="display:flex;"><span> strip_def <span style="color:#81a1c1">=</span> strip_consts<span style="color:#eceff4">(</span>graph_def<span style="color:#eceff4">,</span> max_const_size<span style="color:#81a1c1">=</span>max_const_size<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> code <span style="color:#81a1c1">=</span> <span style="color:#a3be8c">&#34;&#34;&#34; +</span></span></span><span style="display:flex;"><span><span style="color:#a3be8c"> &lt;script src=&#34;//cdnjs.cloudflare.com/ajax/libs/polymer/0.3.3/platform.js&#34;&gt;&lt;/script&gt; +</span></span></span><span style="display:flex;"><span><span style="color:#a3be8c"> &lt;script&gt; +</span></span></span><span style="display:flex;"><span><span style="color:#a3be8c"> function load() {\{ +</span></span></span><span style="display:flex;"><span><span style="color:#a3be8c"> document.getElementById(&#34;</span><span style="color:#a3be8c">{id}</span><span style="color:#a3be8c">&#34;).pbtxt = </span><span style="color:#a3be8c">{data}</span><span style="color:#a3be8c">; +</span></span></span><span style="display:flex;"><span><span style="color:#a3be8c"> }\} +</span></span></span><span style="display:flex;"><span><span style="color:#a3be8c"> &lt;/script&gt; +</span></span></span><span style="display:flex;"><span><span style="color:#a3be8c"> &lt;link rel=&#34;import&#34; href=&#34;https://tensorboard.appspot.com/tf-graph-basic.build.html&#34; onload=load()&gt; +</span></span></span><span style="display:flex;"><span><span style="color:#a3be8c"> &lt;div style=&#34;height:600px&#34;&gt; +</span></span></span><span style="display:flex;"><span><span style="color:#a3be8c"> &lt;tf-graph-basic id=&#34;</span><span style="color:#a3be8c">{id}</span><span style="color:#a3be8c">&#34;&gt;&lt;/tf-graph-basic&gt; +</span></span></span><span style="display:flex;"><span><span style="color:#a3be8c"> &lt;/div&gt; +</span></span></span><span style="display:flex;"><span><span style="color:#a3be8c"> &#34;&#34;&#34;</span><span style="color:#81a1c1">.</span>format<span style="color:#eceff4">(</span>data<span style="color:#81a1c1">=</span><span style="color:#81a1c1">repr</span><span style="color:#eceff4">(</span><span style="color:#81a1c1">str</span><span style="color:#eceff4">(</span>strip_def<span style="color:#eceff4">)),</span> <span style="color:#81a1c1">id</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#39;graph&#39;</span><span style="color:#81a1c1">+</span><span style="color:#81a1c1">str</span><span style="color:#eceff4">(</span>np<span style="color:#81a1c1">.</span>random<span style="color:#81a1c1">.</span>rand<span style="color:#eceff4">()))</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> iframe <span style="color:#81a1c1">=</span> <span style="color:#a3be8c">&#34;&#34;&#34; +</span></span></span><span style="display:flex;"><span><span style="color:#a3be8c"> &lt;iframe seamless style=&#34;width:1200px;height:620px;border:0&#34; srcdoc=&#34;</span><span style="color:#a3be8c">{}</span><span style="color:#a3be8c">&#34;&gt;&lt;/iframe&gt; +</span></span></span><span style="display:flex;"><span><span style="color:#a3be8c"> &#34;&#34;&#34;</span><span style="color:#81a1c1">.</span>format<span style="color:#eceff4">(</span>code<span style="color:#81a1c1">.</span>replace<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#39;&#34;&#39;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#39;&amp;quot;&#39;</span><span style="color:#eceff4">))</span> +</span></span><span style="display:flex;"><span> display<span style="color:#eceff4">(</span>HTML<span style="color:#eceff4">(</span>iframe<span style="color:#eceff4">))</span> +</span></span></code></pre></div><!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"># Simply call this to display the result. Unfortunately it doesn&#39;t save the output together with</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"># the Jupyter notebook, so we can only show a non-interactive image here.</span> +</span></span><span style="display:flex;"><span>show_graph<span style="color:#eceff4">(</span>g<span style="color:#eceff4">)</span> +</span></span></code></pre></div><!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<p><img src="http://i.imgur.com/9sjrCUn.png" alt="cloud hosted tensorboard output"></p> +<!-- raw HTML omitted --> +<h2 id="further-reading">Further reading</h2> +<p>Thats it for this article! Hopefully this article showed you a few tricks that can help you solve TensorFlow problems more +effectively. Here are a few links to related articles and references that further describe TensorBoard.</p> +<ul> +<li><a href="https://www.tensorflow.org/get_started/graph_viz">TensorBoard Graph Visualization</a></li> +<li><a href="https://www.youtube.com/watch?v=eBbEDRsCmv4&amp;index=5&amp;list=PLOU2XLYxmsIKGc_NBoIhTn2Qhraji53cv">Hands-On TensorBoard (TensorFlow Dev Summit 2017) [YouTube]</a></li> +<li><a href="https://github.com/tensorflow/tensorflow/blob/master/tensorflow/tensorboard/README.md">TensorBoard README</a></li> +</ul> +<p>If you have any questions or feedback, please do leave a comment!</p> +<!-- raw HTML omitted --> + + + + + Fibonacci Numbers + https://blog.jakuba.net/2015-08-08-fibonacci-numbers/ + Sat, 08 Aug 2015 00:00:00 +0000 + + https://blog.jakuba.net/2015-08-08-fibonacci-numbers/ + <p>The Fibonacci numbers are a well known recursive sequence, which is +defined as followed</p> +<pre tabindex="0"><code>f[0] = 0 +f[1] = 1 +f[n] = f[n-1] + f[n-2] +</code></pre><p>The question is, how can we calculate them?</p> +<p>The first idea and probably most intuitive way is recursively. Why? +Because the structure of the sequence itself is recursive, which means +the implementation will be very similar to our definition.</p> +<p>I&rsquo;ll chose JavaScript as the implementation language, simply because you +can just open the developer console in your browser and paste in the +snippets to see the results immediately.</p> +<h2 id="1-straightforward-recursive-implementation">1. Straightforward recursive implementation</h2> +<p>We can simply take our definition, add a little bit of syntax, and +voilà, we&rsquo;re done.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> fib<span style="color:#eceff4">(</span>n<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>n <span style="color:#81a1c1">&lt;</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> n<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> fib<span style="color:#eceff4">(</span>n <span style="color:#81a1c1">-</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">+</span> fib<span style="color:#eceff4">(</span>n <span style="color:#81a1c1">-</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>First thing we should test to see if this function actually works.</p> +<pre tabindex="0"><code>&gt; [fib(0), fib(1), fib(2), fib(3), fib(4), fib(5)] +[0, 1, 1, 2, 3, 5] +</code></pre><p>Everything looks nice, but what if we try to calculate a larger number? +What is the largest number that our computer will be able to calculate +using this implementation? You might be tempted to figure this out by +trial and error, but let&rsquo;s try calculating this first.</p> +<p>By a very rough estimate, we could say that a modern computer does +around 1000 000 000 operations per second. One computer might be 10 or +100 times faster than another computer, but that won&rsquo;t really bother us, +since the end result will be the same.</p> +<p>To get any reasonable estimate, we should first figure out the +algorithmic complexity of our little function. At first it seems it +should be linear, since to calculate <code>fib(20)</code> you only need <code>fib(19)</code> +and <code>fib(18)</code>, and so on. Except that <code>fib(19)</code> will calculate <code>fib(18)</code> +again. We can see this more easily by visualizing it as a tree:</p> +<p><img src="https://i.imgur.com/q3ZohJN.png" alt="Fibonacci tree"></p> +<p>As you can see, we&rsquo;re calling <code>fib(n)</code> multiple times for the same +input. Specifically, the height of the tree will be $n$, since the +calculated value decreases by $1$ on each level. If this was a balanced +binary tree, we could easily conclude that it has an exponential number +of nodes, $2^n$ to be specific, but you can already see that one of the +two branches will have fewer children. How many exactly? Let&rsquo;s use a bit +of math.</p> +<p>We can use the same exact formula for calculating the number of nodes, +since:</p> +<ul> +<li>the trees for both <code>fib(0)</code> and <code>fib(1)</code> have <code>1</code> node.</li> +<li>the tree for <code>fib(2)</code> has <code>3</code> nodes, since it needs to calculate +<code>fib(0)</code> and <code>fib(1)</code>, which both have <code>1</code> node, and then put those two together.</li> +<li>the tree for <code>fib(3)</code> has the height <code>1 + fib(2), fib(1)</code></li> +<li>in general, the tree for <code>fib(N)</code> has exactly <code>fib(N-1) + fib(N-2) + 1</code> nodes.</li> +</ul> +<p>Given $f_0 = 0,\ f_1 = 1$ and $f_{n+2} = f_{n+1} + f_{n} + 1$, +we can see that it already grows faster than Fibonacci numbers, so if we +could simplify this and show that the Fibonacci numbers grow +exponentially, it would also mean that the number of nodes in the tree +grow exponentially. There are many ways to derive the closed form formula for Fibonacci +numbers, <a href="http://austinrochford.com/posts/2013-11-01-generating-functions-and-fibonacci-numbers.html">but here&rsquo;s a link to a really nice explanation using generating +functions</a> (the same formula can also be <a href="http://www.the-idea-shop.com/article/218/the-linear-algebra-view-of-the-fibonacci-sequence">derived using linear algebra</a>.) +The resulting formula is:</p> +<p>$$f_n = \frac{1}{\sqrt{5}} \left( \left( \frac{1 + \sqrt{5}}{2} \right)^n - \left(\frac{1 - \sqrt{5}}{2} \right)^n \right)$$</p> +<p>At this point we can see that the Fibonacci numbers grow exponentially, +and so will the number of nodes in the computation tree for our naive +recursive implementation.</p> +<p>This is where the problem comes, since a binary tree of height $n$ will +have $O(2^n)$ nodes, meaning our complexity is exponential (even though +the real complexity is something like $O(1.6^n)$, it is still +exponential.)</p> +<p>For <code>fib(40)</code> this would be roughly $10^{12}$, <code>fib(50)</code> would be $10^{15}$, +and so on. Even if we get a very fast computer, we wouldn&rsquo;t be able to +get anywhere near <code>fib(100)</code>.</p> +<p>We can already see that this algorithm is clearly bad and wouldn&rsquo;t be +very practical in real life (if you ever needed Fibonacci numbers in +real life.), so let&rsquo;s try to improve it.</p> +<p>It feels as if the algorithm should be linear. I bet that if someone +asked you to calculate the first 20 Fibonacci numbers on paper, you&rsquo;d +start with $0$ and $1$, and then just iterate forward.</p> +<h2 id="2-recursive-implementation-with-dynamic-programming">2. Recursive implementation with dynamic programming</h2> +<p>Ideally we&rsquo;d like to keep our simple recursive implementation while +improving the performance to a point where it&rsquo;s comparable to an +iterative solution (in terms of speed.) Earlier we established that the +main bottleneck lies in the repetitive computations.</p> +<p>We&rsquo;ll use dynamic programming to fix this, which basically introduces a +cache (or a memoization mechanism, also called a dynamic programming +table) which is used to store the intermediary result. Once we compute a +number for a specific parameter, we&rsquo;ll store it in the table and never +compute it again. This way we only need to compute each number once, +landing at linear time complexity.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> table <span style="color:#81a1c1">=</span> <span style="color:#eceff4">[</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> fib<span style="color:#eceff4">(</span>n<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">typeof</span> table<span style="color:#eceff4">[</span>n<span style="color:#eceff4">]</span> <span style="color:#81a1c1">!==</span> <span style="color:#a3be8c">&#34;undefined&#34;</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> table<span style="color:#eceff4">[</span>n<span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> table<span style="color:#eceff4">[</span>n<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> fib<span style="color:#eceff4">(</span>n <span style="color:#81a1c1">-</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">+</span> fib<span style="color:#eceff4">(</span>n <span style="color:#81a1c1">-</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> table<span style="color:#eceff4">[</span>n<span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>Note that we don&rsquo;t need to resize the array to fit the values. This is +only possible due to JavaScript&rsquo;s array implementation, which behaves a +lot more like hash-maps than like arrays.</p> +<p>While we did speed up the algorithm significantly, we also traded +computation time for memory, as computing <code>fib(N)</code> will require a table of +size <code>N</code> to store the intermediate results. Before optimizing this +further, we can look at one more dynamic programming solution.</p> +<p>In general there are two ways to approach dynamic programming. One is +top-down, which is what we&rsquo;ve done in the previous example, and the +second one is bottom-up, which is shown in the next snippet.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> fib<span style="color:#eceff4">(</span>n<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> table <span style="color:#81a1c1">=</span> <span style="color:#eceff4">[</span><span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">for</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">var</span> i <span style="color:#81a1c1">=</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">;</span> i <span style="color:#81a1c1">&lt;=</span> n<span style="color:#eceff4">;</span> i<span style="color:#81a1c1">++</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> table<span style="color:#eceff4">[</span>i<span style="color:#eceff4">]</span> <span style="color:#81a1c1">=</span> table<span style="color:#eceff4">[</span>i <span style="color:#81a1c1">-</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1">+</span> table<span style="color:#eceff4">[</span>i <span style="color:#81a1c1">-</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> table<span style="color:#eceff4">[</span>n<span style="color:#eceff4">];</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>Highlighting the differences between top-down and bottom-up:</p> +<ul> +<li>top-down generally starts at the solution, and recursively computes +all the dependencies using memoization</li> +<li>bottom-up starts builds up bigger solutions from smaller ones, until +it reaches the final solution</li> +</ul> +<p>This is an obviously simple example, but it is quite useful to know both +of these approaches, as some problems are easier to solve top-down, and +some are easier to solve using the bottom-up approach.</p> +<p>Regardless of which approach you chose, it still uses $O(N)$ memory. +While this is not ideal if you just want to compute a single value, +having the table pre-computed might come in very handy if you&rsquo;re calling +the function often to get different Fibonacci numbers. I&rsquo;ll leave it as +an exercise to the reader to modify the bottom-up approach to remember +the cached values between the calls, and only compute the needed part of +the table, such that calling <code>fib(10)</code> and then <code>fib(15)</code> would compute +the first 10 Fibonacci numbers only once.</p> +<h2 id="3-iteration">3. Iteration</h2> +<p>Last but not least, we can get rid of the memoization table, and only +compute the n-th number. This is rather easy by modifying the bottom-up +dynamic programming approach.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">function</span> fib<span style="color:#eceff4">(</span>n<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> x <span style="color:#81a1c1">=</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> y <span style="color:#81a1c1">=</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> <span style="color:#eceff4">(</span>n <span style="color:#81a1c1">&gt;</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">for</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">var</span> i <span style="color:#81a1c1">=</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">;</span> i <span style="color:#81a1c1">&lt;=</span> n<span style="color:#eceff4">;</span> i<span style="color:#81a1c1">++</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> tmp <span style="color:#81a1c1">=</span> y<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> y <span style="color:#81a1c1">=</span> x <span style="color:#81a1c1">+</span> y<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> x <span style="color:#81a1c1">=</span> tmp<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">else</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> n<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> y<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>The advantage of this approach is that we get the best of both worlds. +The algorithm runs in linear time and consumes only a constant amount of +memory, and there&rsquo;s no recursion, so we don&rsquo;t have to worry about +stack-limit-exceeded types of errors.</p> +<p>The downside is that if you&rsquo;re going to be calculating lots of Fibonacci +numbers, it will do the work over and over again, while the dynamic +programming approaches could make use of memoization. (Note that the +iterative approach could be also classified as bottom-up dynamic +programming, but for the sake of illustration, I&rsquo;m showing dynamic +programming with an explicit use of a memoization table.)</p> +<h2 id="summary">Summary</h2> +<p>In conclusion, there&rsquo;s no single best solution, and you should pick one +based on your use case. While Fibonacci numbers are a very simple +example, you can already see that there are multiple approaches to the +same problem, without a clear winner.</p> + + + + + Thoughts on OS X Yosemite, Arch Linux and xmonad + https://blog.jakuba.net/2014-11-16-thoughts-on-os-x-yosemite-arch-linux-and-xmonad/ + Sun, 16 Nov 2014 00:00:00 +0000 + + https://blog.jakuba.net/2014-11-16-thoughts-on-os-x-yosemite-arch-linux-and-xmonad/ + <p>I&rsquo;ve been using OS X as my main machine for quite a while now, mainly +because I got into Ruby development, and having a Mac is just the thing +you do when you write Ruby (at least that&rsquo;s what I thought back then.) +One of the main reasons why I really fell in love with the Mac is that +things just work. There is no hassle in setting up your drivers, or +connecting a printer, or getting your favorite app to work. Everything +works out of the box.</p> +<p>We even have homebrew, which is really nice, as long as the thing you +need has a formula that someone has tried before. This is where things +start to get a bit hairy sometimes though. Things that are popular +usually work 100%, on the other hand, programs which aren&rsquo;t in the core +repertoire of a Mac developer either don&rsquo;t have have a formula at all, +or it is broken and/or outdated (I know there are things that work +wonderfully on the Mac that don&rsquo;t work so well on other platforms, but +that&rsquo;s not the point here.) To put this in another words, as long as I +was doing what everyone else was doing I really enjoyed the Mac.</p> +<p>One thing I really admired about the Mac is that everything was designed +to be perfect. The key word here is <em>was</em>. We got a whole new user +interface with the OS X Yosemite update, which I actually do like a lot, +but we also got a huge number of buggy and incomplete things. There are +parts of the UI that are clearly broken, especially in the dark skin. +Handoff and continuity works only when it wants to work, and when it +does, it is really slow. The most annoying thing is that when somebody +calls me on my phone, and the Mac start ringing, and I pickup the phone +because I have it close, the Mac keeps ringing loudly for another 3-5 +seconds, making it impossible to hear the person on the phone. While +this might seem really minor, it gets so annoying that I turned off the +feature after 2-3 phone calls. There are more things like this that are +tiny and broken, it just isn&rsquo;t the Apple it used to be.</p> +<p>This is when I decided that my next computer isn&rsquo;t going to be a Mac.</p> +<h2 id="choosing-the-right-linux-distro">Choosing the right Linux distro</h2> +<p>I&rsquo;ve always been using Linux on the side, mostly because you can get a +tiny 13&quot; Lenovo for 1/3rd of the price of a Macbook Air (Macbook Air +starts at about $1500 in my country, while the Lenovo I&rsquo;m typing on +right now costed about $500.) I always just installed Ubuntu, since +that&rsquo;s the thing that works.</p> +<p>The thing is that I never really liked Ubuntu itself. It&rsquo;s an OK +distribution, and I would recommend it to anyone who isn&rsquo;t familiar with +Linux, just because you can get it working really quickly and there are +no surprises on the way.</p> +<p>But I don&rsquo;t want to be a casual Linux user anymore, I want to customize +everything based on my needs. I don&rsquo;t want to use 95% of the apps that +come installed with Ubuntu, not even Gnome. The reason why I used it is +because it installed in almost a <em>one click install</em>, but that&rsquo;s a poor +reason to choose a distribution.</p> +<p>This is where I made the choice to go with Arch Linux. I tried it once a +few years ago, but it didn&rsquo;t really stick back then, becuase my +mentality was to <em>install everything and make it look like a Mac</em>, which +obviously didn&rsquo;t work because I was lacking the Mac apps.</p> +<p>But now I think I finally understand the philosophy that one should +follow when using a distribution like Arch Linux.</p> +<h2 id="xmonad">xmonad</h2> +<p>Choosing a window manager was probably the easiest decision. At first I +thought about not using a GUI at all, and just live in a tmux session, +but that wouldn&rsquo;t really work with the web-based development that I do +these days, so I just grabbed the next closest thing to tmux, which is +<em>xmonad</em>.</p> +<p>It&rsquo;s been only a few days, but I can already feel the power. Just being +able to hit the keyboard once and have a terminal pop up <em>instantly</em> is +an amazing feature. I&rsquo;m not sure if it&rsquo;s the terminal emulator I&rsquo;m +using, or if it&rsquo;s xmonad, but opening a new terminal is <em>really, really, +really fast</em>. If I didn&rsquo;t have such a slow <code>~/.zshrc</code> it would open as +fast as I let go of the keyboard, but right now there is about 100ms +delay (yeah I&rsquo;m gonna have to optimize my zsh.) This might not seem like +a big deal, but actually being able to open a terminal at any time, type +one command, and immediately close it is <em>amazing</em>. I can be browsing +the web and see something I want to try, and without grabbing the mouse +just open a split terminal window and re-write the command from the web +page, then close the terminal and keep browsing, all without ever +touching the mouse.</p> +<p>I&rsquo;m still waiting to try this on a bigger screen than my tiny 13&quot;, but +I&rsquo;m pretty sure that once I run this on a big screen, I won&rsquo;t be able to +go back to using a regular ol&rsquo; OS X (yes there are xmonad-like things +for OS X, but they don&rsquo;t really work in my testing.)</p> + + + + + Parsing CSS with Parsec + https://blog.jakuba.net/2014-08-10-parsing-css-with-parsec/ + Sun, 10 Aug 2014 00:00:00 +0000 + + https://blog.jakuba.net/2014-08-10-parsing-css-with-parsec/ + <p>This article is a small introduction to +<a href="http://hackage.haskell.org/package/parsec">Parsec</a>, the Haskell parser +combinator library for Haskell. We&rsquo;ll use it to parse simple CSS file +such as the following.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-css" data-lang="css"><span style="display:flex;"><span><span style="color:#eceff4">.</span><span style="color:#8fbcbb">container</span> <span style="color:#81a1c1">h1</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">color</span><span style="color:#eceff4">:</span> <span style="color:#81a1c1">rgba</span><span style="color:#eceff4">(</span><span style="color:#b48ead">255</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">,</span> <span style="color:#b48ead">0.9</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">font-size</span><span style="color:#eceff4">:</span> <span style="color:#b48ead">24</span><span style="color:#81a1c1">px</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>First we need to figure out our data structure which will represent the +syntax tree. Since this is just an introduction, we&rsquo;ll go easy and +ignore features like media queries.</p> +<p>In order to create the structure we need to figure out how to name +things. We can look at the <a href="http://www.w3.org/TR/CSS2/grammar.html">grammar definition for CSS +2.1</a> to figure out how things +are named, from which we can tell that the main unit is a <code>ruleset</code>, has +a <code>selector</code> and a list of <code>declarations</code>. Let&rsquo;s call it a <code>rule</code> +instead of a <code>declaration</code> to keep things short. Each rule then has a +<code>property</code> and a <code>value</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">type</span> <span style="color:#81a1c1">Selector</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">String</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">Rule</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Rule</span> <span style="color:#81a1c1">String</span> <span style="color:#81a1c1">String</span> <span style="color:#81a1c1;font-weight:bold">deriving</span> <span style="color:#81a1c1">Show</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">Ruleset</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Ruleset</span> <span style="color:#81a1c1">Selector</span> <span style="color:#eceff4">[</span><span style="color:#81a1c1">Rule</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1;font-weight:bold">deriving</span> <span style="color:#81a1c1">Show</span> +</span></span></code></pre></div><h2 id="basic-parsec-combinators">Basic parsec combinators</h2> +<p>The way that parsec work is that you build up small parsers and combine +them into bigger ones. We could write a parser for a rule, such as +<code>color: red;</code>, which would first parse a property, then a colon, then +some optional spaces and finally a value with an optional semicolon at +the end.</p> +<p>Here are some basic parsers from the Parsec library.</p> +<ul> +<li><code>char</code> - Parses a single character.</li> +<li><code>string</code> - Parses an arbitrary string.</li> +<li><code>optional</code> - Takes a parser and makes it optional.</li> +<li><code>many</code> - Takes a parser for a single item and makes it into a parser for 0 to N items.</li> +<li><code>many1</code> - Same as <code>many</code>, only that it requires at least one.</li> +<li><code>letter</code> - Parses any letter.</li> +<li><code>digit</code> - Parses a digit.</li> +</ul> +<p>To parse a colon we could do <code>char ':'</code>. If that colon was optional, we +can just combine it with the <code>optional</code> combinator, such as <code>optional (char ':')</code>, and so on.</p> +<p>Here&rsquo;s how a simple parser for <code>Rule</code> could look like.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">import</span> <span style="color:#8fbcbb">Text.Parsec</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">import</span> <span style="color:#8fbcbb">Text.Parsec.String</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">rule</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Parser</span> <span style="color:#81a1c1">Rule</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">rule</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> p <span style="color:#81a1c1;font-weight:bold">&lt;-</span> many1 letter +</span></span><span style="display:flex;"><span> char <span style="color:#a3be8c">&#39;:&#39;</span> +</span></span><span style="display:flex;"><span> optional <span style="color:#eceff4">(</span>char <span style="color:#a3be8c">&#39; &#39;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> v <span style="color:#81a1c1;font-weight:bold">&lt;-</span> many1 letter +</span></span><span style="display:flex;"><span> optional <span style="color:#eceff4">(</span>char <span style="color:#a3be8c">&#39;;&#39;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1">$</span> <span style="color:#81a1c1">Rule</span> p v +</span></span></code></pre></div><p>You might have already noticed that <code>Parser</code> is indeed a Monad, which is +why we&rsquo;re using the <code>do</code> notation, and why we are able to combine many +small parsers together. This is where the power of Parsec comes in, +because it is very easy to combine small parsers to build something that +you can use in the real world.</p> +<p>Now comes the time to test our parser. Parsec defines a function called +<code>parse</code>, which accepts a parser, a source name and a source string, and +returns <code>Either</code> a <code>ParseError</code> if our parsing failed, or the parsed +value.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1;font-weight:bold">import</span> <span style="color:#8fbcbb">Text.Parsec</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse <span style="color:#eceff4">(</span>char <span style="color:#a3be8c">&#39;:&#39;</span><span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#34;test parser&#34;</span> <span style="color:#a3be8c">&#34;:&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Right</span> <span style="color:#a3be8c">&#39;:&#39;</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse <span style="color:#eceff4">(</span>char <span style="color:#a3be8c">&#39;:&#39;</span><span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#34;test parser&#34;</span> <span style="color:#a3be8c">&#34;a&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Left</span> <span style="color:#a3be8c">&#34;test parser&#34;</span> <span style="color:#eceff4">(</span>line <span style="color:#b48ead">1</span><span style="color:#eceff4">,</span> column <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span><span style="color:#81a1c1">:</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">unexpected</span> <span style="color:#a3be8c">&#34;a&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">expecting</span> <span style="color:#a3be8c">&#34;:&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse <span style="color:#eceff4">(</span>many1 letter<span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#34;test parser&#34;</span> <span style="color:#a3be8c">&#34;hello&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Right</span> <span style="color:#a3be8c">&#34;hello&#34;</span> +</span></span></code></pre></div><p>We might also need to say something like <em>parse any number of letters or +digits</em>. This is where the <code>&lt;|&gt;</code> combinator comes in, which allows us to +say the <em>or</em> part. It takes two parsers as arguments and returns a new +parser, which tries to parse with the first one, and if it fails tries +the second one.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse <span style="color:#eceff4">(</span>many1 <span style="color:#81a1c1">$</span> letter <span style="color:#81a1c1">&lt;|&gt;</span> digit<span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#34;test parser&#34;</span> <span style="color:#a3be8c">&#34;hello123&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Right</span> <span style="color:#a3be8c">&#34;hello123&#34;</span> +</span></span></code></pre></div><h1 id="when-parsing-fails">When parsing fails</h1> +<p>There is one thing very important to understand here. As the parsers try +to parse the input, they consume it. If you use <code>&lt;|&gt;</code> to combine two +parsers together, and the first parser fails after already consuming +some input, the second parser will continue where the first one left +off. Here&rsquo;s an example that illustrates this.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse <span style="color:#eceff4">(</span>string <span style="color:#a3be8c">&#34;hay&#34;</span> <span style="color:#81a1c1">&lt;|&gt;</span> string <span style="color:#a3be8c">&#34;hoy&#34;</span><span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#34;test parser&#34;</span> <span style="color:#a3be8c">&#34;hoy&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Left</span> <span style="color:#a3be8c">&#34;test parser&#34;</span> <span style="color:#eceff4">(</span>line <span style="color:#b48ead">1</span><span style="color:#eceff4">,</span> column <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span><span style="color:#81a1c1">:</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">unexpected</span> <span style="color:#a3be8c">&#34;o&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">expecting</span> <span style="color:#a3be8c">&#34;hay&#34;</span> +</span></span></code></pre></div><p>We&rsquo;re trying to parse either <code>&quot;hay&quot;</code> or <code>&quot;hoy&quot;</code>, giving it an input of +<code>&quot;hoy&quot;</code>. It seems that this should obviously succeed, but it doesn&rsquo;t, +because the first parser consumes the first character <code>&quot;h&quot;</code> and then it +fails.</p> +<p>We could write rewrite this in another way.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse <span style="color:#eceff4">(</span>char <span style="color:#a3be8c">&#39;h&#39;</span> <span style="color:#81a1c1">&gt;&gt;</span> <span style="color:#eceff4">(</span>string <span style="color:#a3be8c">&#34;ey&#34;</span> <span style="color:#81a1c1">&lt;|&gt;</span> string <span style="color:#a3be8c">&#34;oy&#34;</span><span style="color:#eceff4">))</span> <span style="color:#a3be8c">&#34;test parser&#34;</span> <span style="color:#a3be8c">&#34;hoy&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Right</span> <span style="color:#a3be8c">&#34;oy&#34;</span> +</span></span></code></pre></div><p>If we used a do block we could&rsquo;ve actually achieved the end result of +parsing the whole <code>&quot;hoy&quot;</code> string, but there&rsquo;s a much easier way, by +using <code>try</code>.</p> +<p>Using <code>try</code> on any parser makes it backtrack when it fails while +consuming a part of the input.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse <span style="color:#eceff4">(</span>try <span style="color:#eceff4">(</span>string <span style="color:#a3be8c">&#34;hay&#34;</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;|&gt;</span> string <span style="color:#a3be8c">&#34;hoy&#34;</span><span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#34;test parser&#34;</span> <span style="color:#a3be8c">&#34;hoy&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Right</span> <span style="color:#a3be8c">&#34;hoy&#34;</span> +</span></span></code></pre></div><p>Note that we only need to use <code>try</code> with our first parser, since there +is nothing left to do if the second parser fails. <code>try</code> doesn&rsquo;t affect +how the parser works, only what happens when it fails.</p> +<p>The bottom line here is, if you&rsquo;re combining together multiple parsers +where one could consume some input and then fail, use <code>try</code>. There are +cases when you don&rsquo;t need to do this, such as when we did <code>letter &lt;|&gt; digit</code>. Since those two parsers don&rsquo;t overlap in their domain, we don&rsquo;t +need to use <code>try</code> there.</p> +<p>The reason why parsec behaves this way is simply because of performance. +Careless usage of <code>try</code> can make the parser slower, but since we&rsquo;re just +trying to understand how things work, we don&rsquo;t need to worry about this.</p> +<h2 id="the-css-parser">The CSS parser</h2> +<p>Before we move on any further, let&rsquo;s improve our original <code>rule</code> parser. +We didn&rsquo;t really account for spaces, since CSS rules can be indented and +there can be arbitrary number of spaces after the <code>:</code>, and values can +have more than just letters, such as <code>#FFF</code>.</p> +<p>We can use the <code>spaces</code> parser which skips <em>zero or more whitespace characters</em>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">rule</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Parser</span> <span style="color:#81a1c1">Rule</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">rule</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> p <span style="color:#81a1c1;font-weight:bold">&lt;-</span> many1 letter +</span></span><span style="display:flex;"><span> char <span style="color:#a3be8c">&#39;:&#39;</span> +</span></span><span style="display:flex;"><span> spaces +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> v <span style="color:#81a1c1;font-weight:bold">&lt;-</span> many1 letter +</span></span><span style="display:flex;"><span> char <span style="color:#a3be8c">&#39;;&#39;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1">$</span> <span style="color:#81a1c1">Rule</span> p v +</span></span></code></pre></div><p>Next we need to figure out how to tell parsec that we also want things +other than just letters in the property value. We could use <code>oneOf</code> to +name all of the symbols we&rsquo;d like to accept, such as <code>oneOf &quot;#()%&quot;</code>, +which parses one character out of the given set. But to keep things +simple, let&rsquo;s just say that the value can be <em>anything but a <code>;</code></em>. We +can use the <code>noneOf</code> combinator for that. We&rsquo;ll also make the <code>;</code> +non-optional to save ourselves some trouble, and accept any number of +whitespace after the whole rule definition.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">rule</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Parser</span> <span style="color:#81a1c1">Rule</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">rule</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> p <span style="color:#81a1c1;font-weight:bold">&lt;-</span> many1 letter +</span></span><span style="display:flex;"><span> char <span style="color:#a3be8c">&#39;:&#39;</span> +</span></span><span style="display:flex;"><span> spaces +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> v <span style="color:#81a1c1;font-weight:bold">&lt;-</span> many1 <span style="color:#eceff4">(</span>noneOf <span style="color:#a3be8c">&#34;;&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> char <span style="color:#a3be8c">&#39;;&#39;</span> +</span></span><span style="display:flex;"><span> spaces +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1">$</span> <span style="color:#81a1c1">Rule</span> p v +</span></span></code></pre></div><p>Let&rsquo;s test this out.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse rule <span style="color:#a3be8c">&#34;css parser&#34;</span> <span style="color:#a3be8c">&#34;background: #fafafa;&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Right</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Rule</span> <span style="color:#a3be8c">&#34;background&#34;</span> <span style="color:#a3be8c">&#34;#fafafa&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse rule <span style="color:#a3be8c">&#34;css parser&#34;</span> <span style="color:#a3be8c">&#34;background: rgba(255, 255, 255, 0.3);&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Right</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Rule</span> <span style="color:#a3be8c">&#34;background&#34;</span> <span style="color:#a3be8c">&#34;rgba(255, 255, 255, 0.3)&#34;</span><span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>We can even try parsing multiple rules at once using <code>many1</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse <span style="color:#eceff4">(</span>many1 rule<span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#34;css parser&#34;</span> <span style="color:#a3be8c">&#34;background: rgba(255, 255, 255, 0.3); color: red;</span><span style="color:#ebcb8b">\n</span><span style="color:#a3be8c">border: 1px solid black;&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Right</span> <span style="color:#eceff4">[</span><span style="color:#81a1c1">Rule</span> <span style="color:#a3be8c">&#34;background&#34;</span> <span style="color:#a3be8c">&#34;rgba(255, 255, 255, 0.3)&#34;</span><span style="color:#eceff4">,</span><span style="color:#81a1c1">Rule</span> <span style="color:#a3be8c">&#34;color&#34;</span> <span style="color:#a3be8c">&#34;red&#34;</span><span style="color:#eceff4">,</span><span style="color:#81a1c1">Rule</span> <span style="color:#a3be8c">&#34;border&#34;</span> <span style="color:#a3be8c">&#34;1px solid black&#34;</span><span style="color:#eceff4">]</span> +</span></span></code></pre></div><p>Now moving onto the parser for a whole ruleset. Let&rsquo;s do the same thing +as we did with values and say that <em>a selector can be any character +except for {</em>. Next we have the <code>{</code>, followed by any number of spaces, +followed by a list of rules, followed by a closing <code>}</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">ruleset</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Parser</span> <span style="color:#81a1c1">Ruleset</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">ruleset</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> s <span style="color:#81a1c1;font-weight:bold">&lt;-</span> many1 <span style="color:#eceff4">(</span>noneOf <span style="color:#a3be8c">&#34;{&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> char <span style="color:#a3be8c">&#39;{&#39;</span> +</span></span><span style="display:flex;"><span> spaces +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> r <span style="color:#81a1c1;font-weight:bold">&lt;-</span> many1 rule +</span></span><span style="display:flex;"><span> char <span style="color:#a3be8c">&#39;}&#39;</span> +</span></span><span style="display:flex;"><span> spaces +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1">$</span> <span style="color:#81a1c1">Ruleset</span> s r +</span></span></code></pre></div><p>Let&rsquo;s test this out.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse ruleset <span style="color:#a3be8c">&#34;css parser&#34;</span> <span style="color:#a3be8c">&#34;p { color: red; }&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Right</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Ruleset</span> <span style="color:#a3be8c">&#34;p &#34;</span> <span style="color:#eceff4">[</span><span style="color:#81a1c1">Rule</span> <span style="color:#a3be8c">&#34;color&#34;</span> <span style="color:#a3be8c">&#34;red&#34;</span><span style="color:#eceff4">])</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse ruleset <span style="color:#a3be8c">&#34;css parser&#34;</span> <span style="color:#a3be8c">&#34;p { background: #fafafa;</span><span style="color:#ebcb8b">\n</span><span style="color:#a3be8c"> color: red; }&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Right</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Ruleset</span> <span style="color:#a3be8c">&#34;p &#34;</span> <span style="color:#eceff4">[</span><span style="color:#81a1c1">Rule</span> <span style="color:#a3be8c">&#34;background&#34;</span> <span style="color:#a3be8c">&#34;#fafafa&#34;</span><span style="color:#eceff4">,</span><span style="color:#81a1c1">Rule</span> <span style="color:#a3be8c">&#34;color&#34;</span> <span style="color:#a3be8c">&#34;red&#34;</span><span style="color:#eceff4">])</span> +</span></span></code></pre></div><p>And everything seems to be working properly. You might notice that our +selector is being parsed as <code>&quot;p &quot;</code> instead of just <code>&quot;p&quot;</code>. This is +because we were too relaxed on our definition, but that&rsquo;s easy to fix. +But first let&rsquo;s do a bit of refactoring.</p> +<h2 id="refactoring-the-parser-using-applicative">Refactoring the parser using Applicative</h2> +<p>Because the <code>Parser</code> monad is also an instance of <code>Applicative</code>, we can +use a lot of the combinators that <code>Applicative</code> gives us to cleanup our +code. The most useful ones are <code>*&gt;</code> and <code>&lt;*</code>, where <code>*&gt;</code> takes two +parsers, runs the first one, throws away the result, then runs the +second one and returns its result (exactly the same as <code>&gt;&gt;</code> does for +monads). <code>&lt;*</code> does the same thing, but the other way around, here are a +couple of examples.</p> +<p>The reason why I&rsquo;m hiding the <code>&lt;|&gt;</code> in the import here is because we +need the definition from Parsec, not from Applicative.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1;font-weight:bold">import</span> <span style="color:#8fbcbb">Control.Applicative</span> <span style="color:#81a1c1;font-weight:bold">hiding</span> <span style="color:#eceff4">((</span><span style="color:#81a1c1">&lt;|&gt;</span><span style="color:#eceff4">))</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse <span style="color:#eceff4">(</span>spaces <span style="color:#81a1c1">*&gt;</span> string <span style="color:#a3be8c">&#34;hello&#34;</span><span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#34;test parser&#34;</span> <span style="color:#a3be8c">&#34; hello&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Right</span> <span style="color:#a3be8c">&#34;hello&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse <span style="color:#eceff4">(</span>char <span style="color:#a3be8c">&#39;(&#39;</span> <span style="color:#81a1c1">*&gt;</span> string <span style="color:#a3be8c">&#34;hello&#34;</span> <span style="color:#81a1c1">&lt;*</span> char <span style="color:#a3be8c">&#39;)&#39;</span><span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#34;test parser&#34;</span> <span style="color:#a3be8c">&#34;(hello)&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Right</span> <span style="color:#a3be8c">&#34;hello&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse <span style="color:#eceff4">(</span>char <span style="color:#a3be8c">&#39;;&#39;</span> <span style="color:#81a1c1">&lt;*</span> spaces<span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#34;test parser&#34;</span> <span style="color:#a3be8c">&#34;; &#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Right</span> <span style="color:#a3be8c">&#39;;&#39;</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse <span style="color:#eceff4">(</span>char <span style="color:#a3be8c">&#39;;&#39;</span> <span style="color:#81a1c1">&lt;*</span> spaces<span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#34;test parser&#34;</span> <span style="color:#a3be8c">&#34;; </span><span style="color:#ebcb8b">\n\n</span><span style="color:#a3be8c">&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Right</span> <span style="color:#a3be8c">&#39;;&#39;</span> +</span></span></code></pre></div><p>As you can see the usage is pretty straightforward. We could write the +same thing using a <code>do</code> notation, but using the Applicative combinators +make the code easier to read once you get used to them. You can think of +them as pointing in the direction of the result.</p> +<p>Here&rsquo;s how we could refactor our rule parser.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">rule</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Parser</span> <span style="color:#81a1c1">Rule</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">rule</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> p <span style="color:#81a1c1;font-weight:bold">&lt;-</span> many1 letter <span style="color:#81a1c1">&lt;*</span> char <span style="color:#a3be8c">&#39;:&#39;</span> <span style="color:#81a1c1">&lt;*</span> spaces +</span></span><span style="display:flex;"><span> v <span style="color:#81a1c1;font-weight:bold">&lt;-</span> many1 <span style="color:#eceff4">(</span>noneOf <span style="color:#a3be8c">&#34;;&#34;</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;*</span> char <span style="color:#a3be8c">&#39;;&#39;</span> <span style="color:#81a1c1">&lt;*</span> spaces +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1">$</span> <span style="color:#81a1c1">Rule</span> p v +</span></span></code></pre></div><p>We can even define a helper that would take a parser and apply <code>&lt;* spaces</code> to it, since we&rsquo;re using that quite a lot, but this is just a +matter of taste.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">paddedChar</span> c <span style="color:#81a1c1;font-weight:bold">=</span> char c <span style="color:#81a1c1">&lt;*</span> spaces +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">rule</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Parser</span> <span style="color:#81a1c1">Rule</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">rule</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> p <span style="color:#81a1c1;font-weight:bold">&lt;-</span> many1 letter <span style="color:#81a1c1">&lt;*</span> paddedChar <span style="color:#a3be8c">&#39;:&#39;</span> +</span></span><span style="display:flex;"><span> v <span style="color:#81a1c1;font-weight:bold">&lt;-</span> many1 <span style="color:#eceff4">(</span>noneOf <span style="color:#a3be8c">&#34;;&#34;</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;*</span> paddedChar <span style="color:#a3be8c">&#39;;&#39;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1">$</span> <span style="color:#81a1c1">Rule</span> p v +</span></span></code></pre></div><p>Let&rsquo;s do the same thing for our ruleset parser.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">ruleset</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Parser</span> <span style="color:#81a1c1">Ruleset</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">ruleset</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> s <span style="color:#81a1c1;font-weight:bold">&lt;-</span> many1 <span style="color:#eceff4">(</span>noneOf <span style="color:#a3be8c">&#34;{&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> r <span style="color:#81a1c1;font-weight:bold">&lt;-</span> paddedChar <span style="color:#a3be8c">&#39;{&#39;</span> <span style="color:#81a1c1">*&gt;</span> many1 rule <span style="color:#81a1c1">&lt;*</span> paddedChar <span style="color:#a3be8c">&#39;}&#39;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1">$</span> <span style="color:#81a1c1">Ruleset</span> s r +</span></span></code></pre></div><p>Now that we have refactored everything, it&rsquo;s time to make the selector +parsing more strict. The new parser will be defined as <em>a sequence of +characters consisting of letters, numbers, dots and hashes, separated by +spaces</em>`.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">selector</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Parser</span> <span style="color:#81a1c1">String</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">selector</span> <span style="color:#81a1c1;font-weight:bold">=</span> many1 <span style="color:#eceff4">(</span>oneOf <span style="color:#a3be8c">&#34;.#&#34;</span> <span style="color:#81a1c1">&lt;|&gt;</span> letter <span style="color:#81a1c1">&lt;|&gt;</span> digit<span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;*</span> spaces +</span></span></code></pre></div><p>Then the actual selector for the ruleset will be just many of our +<code>selector</code> parsers in a row, separated by spaces. We&rsquo;ll use the <code>sepBy1</code> +combinator for this, which takes a parser specifying the separator and +returns a list of parsed values.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse <span style="color:#eceff4">(</span>selector <span style="color:#eceff4">`</span>sepBy1<span style="color:#eceff4">`</span> spaces<span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#34;test parser&#34;</span> <span style="color:#a3be8c">&#34;.container h1 &#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Right</span> <span style="color:#eceff4">[</span><span style="color:#a3be8c">&#34;.container&#34;</span><span style="color:#eceff4">,</span><span style="color:#a3be8c">&#34;h1&#34;</span><span style="color:#eceff4">]</span> +</span></span></code></pre></div><p>Now that we&rsquo;ve succesfully parsed the selector, we can combine it back +into a single string using the <code>unwords</code> function from prelude.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">ruleset</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Parser</span> <span style="color:#81a1c1">Ruleset</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">ruleset</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> s <span style="color:#81a1c1;font-weight:bold">&lt;-</span> selector <span style="color:#eceff4">`</span>sepBy1<span style="color:#eceff4">`</span> spaces +</span></span><span style="display:flex;"><span> r <span style="color:#81a1c1;font-weight:bold">&lt;-</span> paddedChar <span style="color:#a3be8c">&#39;{&#39;</span> <span style="color:#81a1c1">*&gt;</span> many1 rule <span style="color:#81a1c1">&lt;*</span> paddedChar <span style="color:#a3be8c">&#39;}&#39;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1">$</span> <span style="color:#81a1c1">Ruleset</span> <span style="color:#eceff4">(</span>unwords s<span style="color:#eceff4">)</span> r +</span></span></code></pre></div><p>And let&rsquo;s test this once again to make sure everything works.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> parse ruleset <span style="color:#a3be8c">&#34;css parser&#34;</span> <span style="color:#a3be8c">&#34;.container h1 { color: red; }&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Right</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Ruleset</span> <span style="color:#a3be8c">&#34;.container h1&#34;</span> <span style="color:#eceff4">[</span><span style="color:#81a1c1">Rule</span> <span style="color:#a3be8c">&#34;color&#34;</span> <span style="color:#a3be8c">&#34;red&#34;</span><span style="color:#eceff4">])</span> +</span></span></code></pre></div><p>As you can see, our selector now doesn&rsquo;t contain the trailing spaces.</p> +<h2 id="closing-thoughts">Closing thoughts</h2> +<p>The parser we developed in this article is far from complete, but feel +free to extend it to support things like pseudo classes, comments, etc.</p> +<p>While it&rsquo;s not so common to do TDD in Haskell, I&rsquo;d recommend writing a +lot of unit tests for your parser. It&rsquo;s easy to play around in the REPL +and test things out, but once you start composing multiple parsers +together it gets very tedious to have to check different versions of the +string you&rsquo;re parsing every time you make a change. Unlike in regular +Haskell code you can&rsquo;t really rely on the type system that much, since +you&rsquo;re just working with strings.</p> + + + + + Lens Tutorial - Stab & Traversal (Part 2) + https://blog.jakuba.net/2014-08-06-lens-tutorial-stab-traversal-part-2/ + Wed, 06 Aug 2014 00:00:00 +0000 + + https://blog.jakuba.net/2014-08-06-lens-tutorial-stab-traversal-part-2/ + <p>In the <a href="https://blog.jakuba.net/2014/07/14/lens-tutorial-introduction-part-1.html">first article in the series about lenses</a>, +we&rsquo;ve looked at the motivation behind the lens library, and we also +derived the basic type of <code>Lens s a</code>.</p> +<p>In this article we&rsquo;ll go deeper and explain the reasoning beheind the more +generic <code>Lens s t a b</code> type. We&rsquo;ll also take a look at how we can get a multi +focus lens using a <code>Traversal</code>.</p> +<p>Just to reiterate, here&rsquo;s how looks the type we derived in the previous +article.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">type</span> <span style="color:#81a1c1">Lens</span> s a <span style="color:#81a1c1;font-weight:bold">=</span> forall f<span style="color:#81a1c1">.</span> <span style="color:#81a1c1">Functor</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f s +</span></span></code></pre></div><p>What we&rsquo;ll do here is further generalize it so that we can change the type of +the focus.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">type</span> <span style="color:#81a1c1">Lens</span> s t a b <span style="color:#81a1c1;font-weight:bold">=</span> forall f<span style="color:#81a1c1">.</span> <span style="color:#81a1c1">Functor</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f t +</span></span></code></pre></div><p>Now you might be thinking that four type parameters is a bit much, but bear +with me here. If we compare the our <code>Lens s t a b</code> to something like <code>fmap</code>, we +can see a bit resemblance there.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t fmap +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Functor</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f b +</span></span></code></pre></div><p>Much like a function <code>a -&gt; b</code> can be applied on <code>f a</code> to <em>change it&rsquo;s +structure</em> to become an <code>f b</code>. In the same way a <code>Lens s t a b</code> allows us to +change <code>a</code> to <code>b</code>, which changes the <em>shape</em> of <code>s</code> to <code>t</code>. We can also read it +as: <em>A lens allows us to look at <code>a</code> inside an <code>s</code>, and if we can also replace +the <code>a</code> with a <code>b</code>, which will make the <code>s</code> into <code>t</code></em>. Here&rsquo;s a simple example +using tuples.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t <span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;hello&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;world&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">String</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1">String</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t over _1 length <span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;hello&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;world&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Int</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1">String</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> over _1 length <span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;hello&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;world&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#b48ead">5</span><span style="color:#eceff4">,</span><span style="color:#a3be8c">&#34;world&#34;</span><span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>Initially we started out with <code>s :: (String, String)</code> and ended up with <code>t :: (Int, String)</code> by applying a <code>String -&gt; Int</code> function on the first element of +the tuple. The specific type of the <code>_1</code> lens in this case would be <code>Lens (String, String) (Int, String) String Int</code>.</p> +<p>It&rsquo;s important to understand that all of the derivations we made for <code>Lens s a</code> +still hold for <code>Lens s t a b</code>, since it&rsquo;s just a bit more generic. In fact you +can write the following (as it is done in the lens library.)</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">type</span> <span style="color:#81a1c1">Lens&#39;</span> s a <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Lens</span> s s a a +</span></span></code></pre></div><p>I&rsquo;ll leave it as an exercise to the reader to go through all of the steps we +did previously and use <code>Lens s t a b</code> instead.</p> +<h2 id="traversal---the-multi-foci-lens">Traversal - the multi foci lens</h2> +<p><em>Disclaimer: When I say <strong>list</strong> I really mean <code>Data.Traversable</code>, however +using a <strong>list</strong> makes things easier to understand. <a href="https://blog.jakuba.net/2014/07/30/foldable-and-traversable.html">I also wrote an article on +Traversable if you&rsquo;re unfamiliar with +it</a>.</em></p> +<p>While the lenses we&rsquo;ve established so far are useful, they do have their +shortcomings. One example are nested lists, let&rsquo;s see an example.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">User</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">User</span> <span style="color:#81a1c1">String</span> <span style="color:#eceff4">[</span><span style="color:#81a1c1">Post</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1;font-weight:bold">deriving</span> <span style="color:#81a1c1">Show</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">Post</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Post</span> <span style="color:#81a1c1">String</span> <span style="color:#81a1c1;font-weight:bold">deriving</span> <span style="color:#81a1c1">Show</span> +</span></span></code></pre></div><p>Now if I give you a list of users and ask you to give me all of the names of +their posts, you&rsquo;ll probably not be very happy about that. Not that it&rsquo;s +difficult, but some work involved.</p> +<p>With <code>Traversal</code> and <code>traverse</code> we can focus on all elements of a list and do +this in a single step. But first, let&rsquo;s define us some lenses to work with the +types. In a real world application we&rsquo;d use Template Haskell to generate the +lenses automatically, but for the sake of exercise let&rsquo;s do it manually here.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">posts</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens&#39;</span> <span style="color:#81a1c1">User</span> <span style="color:#eceff4">[</span><span style="color:#81a1c1">Post</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">posts</span> f <span style="color:#eceff4">(</span><span style="color:#81a1c1">User</span> n p<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> fmap <span style="color:#eceff4">(</span><span style="color:#88c0d0">\</span>p&#39; <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">User</span> n p&#39;<span style="color:#eceff4">)</span> <span style="color:#eceff4">(</span>f p<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">title</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens&#39;</span> <span style="color:#81a1c1">Post</span> <span style="color:#81a1c1">String</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">title</span> f <span style="color:#eceff4">(</span><span style="color:#81a1c1">Post</span> t<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> fmap <span style="color:#81a1c1">Post</span> <span style="color:#eceff4">(</span>f t<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>We got two lenses, one that focuses on <code>User</code>&rsquo;s posts, and another one for the +post&rsquo;s title. Let&rsquo;s also define us some test data to play around with.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">users</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">[</span><span style="color:#81a1c1">User</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">users</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#eceff4">[</span><span style="color:#81a1c1">User</span> <span style="color:#a3be8c">&#34;john&#34;</span> <span style="color:#eceff4">[</span><span style="color:#81a1c1">Post</span> <span style="color:#a3be8c">&#34;hello&#34;</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1">Post</span> <span style="color:#a3be8c">&#34;world&#34;</span><span style="color:#eceff4">],</span> <span style="color:#81a1c1">User</span> <span style="color:#a3be8c">&#34;bob&#34;</span> <span style="color:#eceff4">[</span><span style="color:#81a1c1">Post</span> <span style="color:#a3be8c">&#34;foobar&#34;</span><span style="color:#eceff4">]]</span> +</span></span></code></pre></div><p>Now lets open up GHCi, load these definitions file, import <code>Control.Lens</code> and +see what we can do.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> view <span style="color:#eceff4">(</span>traverse<span style="color:#81a1c1">.</span>posts<span style="color:#eceff4">)</span> users +</span></span><span style="display:flex;"><span><span style="color:#eceff4">[</span><span style="color:#81a1c1">Post</span> <span style="color:#a3be8c">&#34;hello&#34;</span><span style="color:#eceff4">,</span><span style="color:#81a1c1">Post</span> <span style="color:#a3be8c">&#34;world&#34;</span><span style="color:#eceff4">,</span><span style="color:#81a1c1">Post</span> <span style="color:#a3be8c">&#34;foobar&#34;</span><span style="color:#eceff4">]</span> +</span></span></code></pre></div><p>This seems to do what we want, we gave it a list of users and pulled out a list +of posts. Note that we used <code>traverse</code> every time the current <em>focus</em> was a +list, which is just in the first step on <code>users</code>.</p> +<p>The next step is to go deeper to fetch the post title. If you look at the type +of our current lens <code>traverse.posts</code>, you&rsquo;ll see that it focuses on <code>[Posts]</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t traverse<span style="color:#81a1c1">.</span>posts +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Traversable</span> t<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Applicative</span> f<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">[</span><span style="color:#81a1c1">Post</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">[</span><span style="color:#81a1c1">Post</span><span style="color:#eceff4">])</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t <span style="color:#81a1c1">User</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>t <span style="color:#81a1c1">User</span><span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>In order to reach out to each post, we need to use <code>traverse</code> again. You can +think of <code>traverse</code> as something that allows us to focus on multiple targets at +once, in a similar way that <code>map</code> allows us to apply a function to all elements +of a list.</p> +<ul> +<li>We started with <code>[User]</code>.</li> +<li>We can&rsquo;t directly apply the <code>posts</code> lens, since that requires a <code>User</code>.</li> +<li><code>traverse</code> changes to focus on <code>User</code> inside the <code>[User]</code>.</li> +<li><code>traverse.posts</code> now works, since our target is just a <code>User</code>, so we can compose to get a lens of <code>traverse.posts</code>.</li> +</ul> +<p>It is also important to note here that the lens composition works backwards +than what is usual in Haskell. You can think of it as a sort of object accessor +notation in an object-oriented language, where you&rsquo;d do <code>foo.bar.baz</code>.</p> +<p>Just to make this point crystal clear, here&rsquo;s how function composition works +for regular functions. The <code>*2</code> gets applied <em>before</em> the <code>+1</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#eceff4">((</span><span style="color:#81a1c1">+</span><span style="color:#b48ead">1</span><span style="color:#eceff4">)</span><span style="color:#81a1c1">.</span><span style="color:#eceff4">(</span><span style="color:#81a1c1">*</span><span style="color:#b48ead">2</span><span style="color:#eceff4">))</span> <span style="color:#b48ead">1</span> +</span></span><span style="display:flex;"><span><span style="color:#b48ead">3</span> +</span></span></code></pre></div><p>With lenses it goes the other way and the <code>traverse</code> goes <em>before</em> the <code>posts</code> +lens.</p> +<h2 id="traversing-deeper-and-deeper">Traversing deeper and deeper</h2> +<p>Our previous example worked out just as we wanted, so let&rsquo;s try to go deeper +and actually fetch the title of each <code>Post</code> from our <code>users</code> list.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> view <span style="color:#eceff4">(</span>traverse<span style="color:#81a1c1">.</span>posts<span style="color:#81a1c1">.</span>traverse<span style="color:#81a1c1">.</span>title<span style="color:#eceff4">)</span> users +</span></span><span style="display:flex;"><span><span style="color:#a3be8c">&#34;helloworldfoobar&#34;</span> +</span></span></code></pre></div><p>Huh? This isn&rsquo;t what we wanted at all! Lens must be completely broken?!!?1!</p> +<p>Much like we got <code>[Post]</code> from <code>traverse.posts</code>, it would make sense to get +<code>[String]</code> from <code>traverse.posts.traverse.title</code>, but instead we got one big +<code>String</code> with all of the titles combined. In order to understand why this is +happening we need to look more closely at how <code>traverse</code> works.</p> +<p>Here&rsquo;s a simpler example that we can use to reproduce what we had previously.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> view traverse <span style="color:#eceff4">[</span><span style="color:#a3be8c">&#34;hello&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;world&#34;</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#a3be8c">&#34;helloworld&#34;</span> +</span></span></code></pre></div><p>The reason for this behavior is that if we use <code>view</code> together with <code>traverse</code> +it will use the <code>Monoid</code> instance of our focus and smash them together.</p> +<p>Let&rsquo;s see how this works by inlining the definition of <code>view</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">view</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">view</span> ln s <span style="color:#81a1c1;font-weight:bold">=</span> getConst <span style="color:#81a1c1">$</span> ln <span style="color:#81a1c1">Const</span> s +</span></span></code></pre></div><p>Inlining the arguments we get the following.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> view traverse <span style="color:#eceff4">[</span><span style="color:#a3be8c">&#34;hello&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;world&#34;</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#a3be8c">&#34;helloworld&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> getConst <span style="color:#81a1c1">$</span> traverse <span style="color:#81a1c1">Const</span> <span style="color:#eceff4">[</span><span style="color:#a3be8c">&#34;hello&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;world&#34;</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#a3be8c">&#34;helloworld&#34;</span> +</span></span></code></pre></div><p>We can already see that it is not the <code>lens</code> library that does the magic, it&rsquo;s +the <code>traverse</code> combined with <code>Const</code>. The <code>view</code> just picks the <code>Const</code> +applicative to be used with the <code>traverse</code> function.</p> +<p>Now moving on to inlining definition of <code>traverse</code>, which for a list look like +following.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">traverse</span> <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">=</span> pure <span style="color:#81a1c1">[]</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">traverse</span> f <span style="color:#eceff4">(</span>x<span style="color:#81a1c1">:</span>xs<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> f x <span style="color:#81a1c1">&lt;*&gt;</span> traverse f xs +</span></span></code></pre></div><p>Since this is a recursive function and our list has two elements, we need to +inline it in multiple steps.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">-- Inlined the arguments into the definition.</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> <span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;hello&#34;</span> <span style="color:#81a1c1">&lt;*&gt;</span> traverse f <span style="color:#eceff4">[</span><span style="color:#a3be8c">&#34;world&#34;</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">-- First recursive call to traverse inlined.</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> <span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;hello&#34;</span> <span style="color:#81a1c1">&lt;*&gt;</span> <span style="color:#eceff4">((</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> <span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;world&#34;</span> <span style="color:#81a1c1">&lt;*&gt;</span> traverse f <span style="color:#81a1c1">[]</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">-- Second recursive call to traverse inlined.</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> <span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;hello&#34;</span> <span style="color:#81a1c1">&lt;*&gt;</span> <span style="color:#eceff4">((</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> <span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;world&#34;</span> <span style="color:#81a1c1">&lt;*&gt;</span> pure <span style="color:#81a1c1">[]</span><span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>This whole expression will return a type of <code>Const String [a]</code>, from which we +need to extract the <code>String</code> using <code>getConst</code>, as shown above.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> getConst <span style="color:#81a1c1">$</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> <span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;hello&#34;</span> <span style="color:#81a1c1">&lt;*&gt;</span> <span style="color:#eceff4">((</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> <span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;world&#34;</span> <span style="color:#81a1c1">&lt;*&gt;</span> pure <span style="color:#81a1c1">[]</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#a3be8c">&#34;helloworld&#34;</span> +</span></span></code></pre></div><p>As you can see we&rsquo;re still getting the same result as in the case of <code>view traverse [&quot;hello&quot;, &quot;world&quot;]</code>, which means we&rsquo;re on the right track. But this +still doesn&rsquo;t explain why are the two strings being concatenated together.</p> +<h2 id="const-as-a-monoid">Const as a Monoid</h2> +<p>To understand the concatenation we need to take a look at how the <code>Applicative</code> +instance for <code>Const</code> is implemented, but let&rsquo;s think about this first.</p> +<p><code>Const a b</code> acts as an <code>Functor</code> that <em>pretends</em> to contain a value of type +<code>b</code>, but in reality hides a value of type <code>a</code>. That&rsquo;s why if we have <code>Const Int String</code> and <code>fmap</code> a function of type <code>String</code>, we&rsquo;ll get a <code>Const Int Int</code>, +even though there was no actual value for <code>String</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1;font-weight:bold">let</span> a <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Const</span> <span style="color:#b48ead">3</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Const</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1">String</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t a +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Const</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1">String</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t fmap length a +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Const</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1">Int</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> getConst <span style="color:#81a1c1">$</span> fmap length a +</span></span><span style="display:flex;"><span><span style="color:#b48ead">3</span> +</span></span></code></pre></div><p>If you&rsquo;re having trouble understanding this, <a href="https://blog.jakuba.net/2014/07/14/lens-tutorial-introduction-part-1.html">check out my first article on +Lenses</a> +which explains this in a bit more detail.</p> +<p>Now we&rsquo;re faced with the problem of implementing an <code>Applicative</code> instance. The +problem being that <code>Applicative</code> defines <code>pure :: a -&gt; f a</code>, which takes a +value and lifts it into the <code>Applicative</code>. But because we&rsquo;re working with +<code>Const</code>, there is no actual value being lifted, as in the case of a <code>Functor</code> +where we didn&rsquo;t really apply the function.</p> +<p><strong><code>Const Int String</code> does not contain any <code>String</code>, it only contains the +<code>Int</code>.</strong> That&rsquo;s why if we do <code>pure 3</code> to get back a <code>Const String Int</code>, we must +throw away the <code>3</code> and somehow create a <code>String</code> to hide it into the <code>Const</code>. +We need to have a way to create a value for the type we&rsquo;re hiding. But how do +we do that when we have nothing?</p> +<p>We use a <code>Monoid</code> and <code>mempty</code>!</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Monoid</span> m <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#81a1c1">Applicative</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Const</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> pure <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Const</span> mempty +</span></span></code></pre></div><p>We just throw away the argument to <code>pure</code> and create a new <code>Const</code> hiding the +value returned by <code>mempty</code>, which for a <code>String</code> in our previous example would +be <code>&quot;&quot;</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> getConst <span style="color:#81a1c1">$</span> <span style="color:#eceff4">(</span>pure <span style="color:#b48ead">3</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Const</span> <span style="color:#81a1c1">String</span> <span style="color:#81a1c1">Int</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#a3be8c">&#34;&#34;</span> +</span></span></code></pre></div><p>Next up is the definition of <code>&lt;*&gt;</code>, which is rather simple now that we know +that our hidden value is a <code>Monoid</code>. The way that <code>&lt;*&gt;</code> works is that it takes +two <code>Applicative</code>s and smashes them together. In a general case it would mean +applying the function in the first one to the value in the second one, but +because our <code>Const</code> is just pretending to have a function while it has none, we +do not need to apply it. We just need to find a way to combine our two hidden +monoidal values, which is exactly where <code>mappend</code> will come to play.</p> +<p>We simply extract the hidden values and <code>mappend</code> them together to create a new +<code>Const</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Monoid</span> m <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#81a1c1">Applicative</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Const</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> pure <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Const</span> mempty +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">Const</span> f <span style="color:#81a1c1">&lt;*&gt;</span> <span style="color:#81a1c1">Const</span> x <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Const</span> <span style="color:#eceff4">(</span>f <span style="color:#eceff4">`</span>mappend<span style="color:#eceff4">`</span> x<span style="color:#eceff4">)</span> +</span></span></code></pre></div><h2 id="intuition-behind-view-traverse">Intuition behind <code>view traverse</code></h2> +<p>Finally we can get back to our <code>traverse</code> example and understand why it does +what it does. We ended up with the following expression.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> <span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;hello&#34;</span> <span style="color:#81a1c1">&lt;*&gt;</span> <span style="color:#eceff4">((</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> <span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;world&#34;</span> <span style="color:#81a1c1">&lt;*&gt;</span> pure <span style="color:#81a1c1">[]</span><span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>With the recently gained knowledge we can see that it doesn&rsquo;t matter what +function we apply to our <code>Const</code>. In this case it is <code>(:)</code> but it might as well +be <code>undefined</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> getConst <span style="color:#81a1c1">$</span> undefined <span style="color:#81a1c1">&lt;$&gt;</span> <span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;hello&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#a3be8c">&#34;hello&#34;</span> +</span></span></code></pre></div><p>This means that the whole <code>(:) &lt;$&gt;</code> has absolutely no meaning. It&rsquo;s just there +so that our <code>Const &quot;hello&quot;</code> can take on a type of a function application, so +that we can use <code>&lt;*&gt;</code>. In fact the only thing that does something is the <code>&lt;*&gt;</code> +combinator, which calls <code>mappend</code> on the hidden values, but let&rsquo;s take this +step by step.</p> +<p>First we replace <code>pure []</code> with the actual value it returns in this case.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> <span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;hello&#34;</span> <span style="color:#81a1c1">&lt;*&gt;</span> <span style="color:#eceff4">((</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> <span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;world&#34;</span> <span style="color:#81a1c1">&lt;*&gt;</span> <span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;&#34;</span><span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>Next we can evaluate the expression in the parentheses, which if you look at +our definition of <code>Const</code> will just reduce to the following.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1">Const</span> <span style="color:#81a1c1">$</span> <span style="color:#a3be8c">&#34;world&#34;</span> <span style="color:#eceff4">`</span>mappend<span style="color:#eceff4">`</span> <span style="color:#a3be8c">&#34;&#34;</span> +</span></span></code></pre></div><p>Which evaluates to just <code>Const &quot;world&quot;</code>. Now we&rsquo;re left with the following.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> <span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;hello&#34;</span> <span style="color:#81a1c1">&lt;*&gt;</span> <span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;world&#34;</span> +</span></span></code></pre></div><p>Which again just ends up being:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1">Const</span> <span style="color:#81a1c1">$</span> <span style="color:#a3be8c">&#34;hello&#34;</span> <span style="color:#eceff4">`</span>mappend<span style="color:#eceff4">`</span> <span style="color:#a3be8c">&#34;world&#34;</span> +</span></span></code></pre></div><p>Which evaluates to <code>Const &quot;helloworld&quot;</code>. Our initial expression applied +<code>getConst</code> to the result of this expression, which would just yield +<code>&quot;helloworld&quot;</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> getConst <span style="color:#81a1c1">$</span> <span style="color:#81a1c1">Const</span> <span style="color:#81a1c1">$</span> <span style="color:#a3be8c">&#34;hello&#34;</span> <span style="color:#eceff4">`</span>mappend<span style="color:#eceff4">`</span> <span style="color:#a3be8c">&#34;world&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#a3be8c">&#34;helloworld&#34;</span> +</span></span></code></pre></div><p>There we go, now we have a full understanding of why <code>view traverse</code> requires +the traversed values to be a Monoid.</p> +<p>In the next article we&rsquo;ll focus on some other use cases for <code>traverse</code> and how +to use it with combinators like <code>toListOf</code>, etc.</p> + + + + + Foldable and Traversable + https://blog.jakuba.net/2014-07-30-foldable-and-traversable/ + Wed, 30 Jul 2014 00:00:00 +0000 + + https://blog.jakuba.net/2014-07-30-foldable-and-traversable/ + <p>Before we can get into the more advanced topics on Lenses, it is +important to really understand both <code>Foldable</code> and <code>Traversable</code>, which +is the motivation behind this article.</p> +<p>Let&rsquo;s begin with <code>Foldable</code>. <code>Foldable</code> represents structures which can +be folded. What does that mean? Here are a few examples:</p> +<ul> +<li>Calculating the sum of a list.</li> +<li>Calculating the product of a list.</li> +<li>Folding a tree to get a maximum value.</li> +</ul> +<p>We can describe a <em>fold</em> as <strong><em>taking a structure and reducing it to a +single result</em></strong>. That&rsquo;s also why some languages have a <code>reduce</code> +function instead of a <code>fold</code>, even though they mean the same thing.</p> +<p>It is important to really understand the concept behind a fold in +general, not in terms of specific functions like <code>foldl</code> or <code>foldr</code>. +Whenever you see the word <code>fold</code> in a function name, think <em>reducing a +larger structure to a single result</em>.</p> +<p>Now comes the time to take a look at the <code>Foldable</code> type class.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">class</span> <span style="color:#81a1c1">Foldable</span> t <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> fold <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Monoid</span> m <span style="color:#81a1c1;font-weight:bold">=&gt;</span> t m <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m +</span></span><span style="display:flex;"><span> foldMap <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Monoid</span> m <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> foldr <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b +</span></span><span style="display:flex;"><span> foldr&#39; <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> foldl <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span>b <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b +</span></span><span style="display:flex;"><span> foldl&#39; <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span>b <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> foldr1 <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a +</span></span><span style="display:flex;"><span> foldl1 <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a +</span></span></code></pre></div><p>We won&rsquo;t go into detail on all of these, since <code>foldl</code>, <code>foldr</code>, +<code>foldl'</code>, <code>foldr'</code>, <code>foldl1</code> and <code>foldr1</code> work the same as their +counterparts from <code>Data.List</code>.</p> +<p>What is interesting here is that <code>fold</code> and <code>foldMap</code> require the +elements of the <code>Foldable</code> to be <code>Monoid</code>s. Let&rsquo;s just quickly take a +look at what a <code>Monoid</code> is.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">class</span> <span style="color:#81a1c1">Monoid</span> a <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> mempty <span style="color:#81a1c1;font-weight:bold">::</span> a +</span></span><span style="display:flex;"><span> mappend <span style="color:#81a1c1;font-weight:bold">::</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a +</span></span><span style="display:flex;"><span> mconcat <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">[</span>a<span style="color:#eceff4">]</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a +</span></span></code></pre></div><p>Nothing really special here, <code>Monoid</code> just simply defines a zero element +via <code>mempty</code> and an associative operation <code>mappend</code> for combining two +<code>Monoid</code>s into one. <code>mconcat</code> is just a convenience method which has a +default implementation using <code>mappend</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">mconcat</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">[</span>a<span style="color:#eceff4">]</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">mconcat</span> <span style="color:#81a1c1;font-weight:bold">=</span> foldr mappend mempty +</span></span></code></pre></div><h2 id="fold-and-foldmap">fold and foldMap</h2> +<p>The interesting thing about <code>fold</code> and <code>foldMap</code> is that they use a +<code>Monoid</code> instead of a function to give us the final result. This might +not be obvious at first, but by picking the right <code>Monoid</code> it is +essentialy the same as passing in a function, since it will just use the +<code>mappend</code> defined for that <code>Monoid</code> instance.</p> +<p>One very very very important aspect to understand here is that it is the +<code>fold</code> function that requires the elements of <code>Foldable</code> to have a +<code>Monoid</code> instance, while <code>Foldable</code> itself does not have that +restriction.</p> +<p>The result of this is that we can have something like <code>[Int]</code>, where the +<code>[]</code> is a <code>Foldable</code>, but <code>Int</code> is not a <code>Monoid</code>, though as long as we +don&rsquo;t use any of the functions from <code>Foldable</code> that require a <code>Monoid</code> +we&rsquo;ll be OK. Here&rsquo;s an example</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> foldr1 <span style="color:#eceff4">(</span><span style="color:#81a1c1">+</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">[</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">2</span><span style="color:#eceff4">,</span><span style="color:#b48ead">3</span><span style="color:#eceff4">,</span><span style="color:#b48ead">4</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#b48ead">10</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> fold <span style="color:#eceff4">[</span><span style="color:#a3be8c">&#34;hello&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;world&#34;</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#a3be8c">&#34;helloworld&#34;</span> <span style="color:#616e87;font-style:italic">-- Strings are Monoids using concatenation</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> fold <span style="color:#eceff4">[</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">2</span><span style="color:#eceff4">,</span><span style="color:#b48ead">3</span><span style="color:#eceff4">,</span><span style="color:#b48ead">4</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">&lt;</span>interactive<span style="color:#81a1c1">&gt;:</span><span style="color:#b48ead">1</span><span style="color:#81a1c1">:</span><span style="color:#b48ead">1</span><span style="color:#81a1c1">:</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">No</span> <span style="color:#81a1c1;font-weight:bold">instance</span> for <span style="color:#eceff4">(</span><span style="color:#81a1c1">Monoid</span> a0<span style="color:#eceff4">)</span> arising from a use <span style="color:#81a1c1;font-weight:bold">of</span> <span style="color:#bf616a">‘</span>it<span style="color:#bf616a">’</span> +</span></span></code></pre></div><p>See how the problem only arises when we used <code>fold</code> with <code>Int</code>. We could +however wrap those <code>Int</code>s in a <code>Monoid</code> such as <code>Sum</code> or <code>Product</code> and +<code>fold</code> them then.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> fold <span style="color:#eceff4">[</span><span style="color:#81a1c1">Sum</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1">Sum</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1">Sum</span> <span style="color:#b48ead">3</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1">Sum</span> <span style="color:#b48ead">4</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Sum</span> <span style="color:#eceff4">{</span>getSum <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#b48ead">10</span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>This might seem tedious at first, but remember our <code>Foldable</code> type +class, as it also defines a function that is perfect for this particular +use case: <code>foldMap :: Monoid m =&gt; (a -&gt; m) -&gt; t a -&gt; m</code>. We can read +this as <em>Given a foldable containing things that aren&rsquo;t Monoids, and a +function that can convert a single thing to a Monoid, I&rsquo;ll give you back +a Monoid by traversing the foldable, converting everything to Monoids +and folding them together.</em></p> +<p>Here&rsquo;s our previous example, but now using <code>foldMap</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> foldMap <span style="color:#81a1c1">Sum</span> <span style="color:#eceff4">[</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">2</span><span style="color:#eceff4">,</span><span style="color:#b48ead">3</span><span style="color:#eceff4">,</span><span style="color:#b48ead">4</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Sum</span> <span style="color:#eceff4">{</span>getSum <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#b48ead">10</span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>If you think about this for a little while we might even implement +<code>fold</code> in terms of <code>foldMap</code>. Why? When using <code>foldMap</code> we need to +provide a way to convert each item to a <code>Monoid</code>, but if those items +already are <code>Monoid</code>s, we don&rsquo;t need to do any conversion!</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">fold</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Monoid</span> m <span style="color:#81a1c1;font-weight:bold">=&gt;</span> t m <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">fold</span> xs <span style="color:#81a1c1;font-weight:bold">=</span> foldMap id xs +</span></span></code></pre></div><p>Here&rsquo;s the same in more steps.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t id +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t fold +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Monoid</span> m<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Foldable</span> t<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> t m <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t foldMap +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Monoid</span> m<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Foldable</span> t<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t foldMap id +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Monoid</span> m<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Foldable</span> t<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> t m <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m +</span></span></code></pre></div><p>The actual <code>Foldable</code> type class requires either <code>foldMap</code> or <code>foldr</code>, +but for the sake of this article we won&rsquo;t be looking into <code>foldr</code>.</p> +<h2 id="traversable">Traversable</h2> +<p>Now that we have an understanding of <code>Foldable</code> we can move on to +something more fun, <code>Traversable</code>. <code>Traversable</code> represents data +structures which can be traversed while perserving the shape. This is +why there is no <code>filter</code> or <code>concatMap</code>, since <code>Traversable</code> only +defines a way to move through the data structure, but not a way to +change it.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">class</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Functor</span> t<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Foldable</span> t<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#81a1c1">Traversable</span> t <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> traverse <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Applicative</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>t b<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> sequenceA <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Applicative</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> t <span style="color:#eceff4">(</span>f a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>t a<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>If you look <a href="https://hackage.haskell.org/package/base-4.7.0.0/docs/Data-Traversable.html">in the documentation for +<code>Traversable</code></a> +you might note that there is also <code>mapM</code> and <code>sequence</code>, but we won&rsquo;t be +covering those in this article, since their implementation isn&rsquo;t +interesting and can be done mechanically.</p> +<p>This might look a little intimidating at first, but don&rsquo;t worry, we&rsquo;ll +do this step by step by implementing a <code>Traversable</code> instance for a +list.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Traversable</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> traverse f xs <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> +</span></span></code></pre></div><p>Since the implementation will be recursive we first need to define the +base case for our recursion, which will be the empty list. The type that +we&rsquo;re looking for is <code>f [b]</code>, but because the list we&rsquo;re traversing is +empty, we just need to wrap it in the <code>Applicative</code> context.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Traversable</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> traverse <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">=</span> pure <span style="color:#81a1c1">[]</span> +</span></span><span style="display:flex;"><span> traverse f <span style="color:#eceff4">(</span>x<span style="color:#81a1c1">:</span>xs<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> +</span></span></code></pre></div><p>Next goes the actual recursive implementaion. We have a function <code>f :: a -&gt; f b</code> and a head of the list which has the type <code>a</code>. The only thing we +can do at this point is apply the function.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Traversable</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> traverse <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">=</span> pure <span style="color:#81a1c1">[]</span> +</span></span><span style="display:flex;"><span> traverse f <span style="color:#eceff4">(</span>x<span style="color:#81a1c1">:</span>xs<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> f x +</span></span></code></pre></div><p>This won&rsquo;t typecheck of course, because we&rsquo;re returning <code>f b</code> instead of +<code>f [b]</code>. We could cheat here a little bit and just try to apply a some +function <code>f b -&gt; f [b]</code> to get the result. We can use <code>(:[])</code> which has +a type of <code>a -&gt; [a]</code> and <code>fmap</code> it on what we have.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Traversable</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> traverse <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">=</span> pure <span style="color:#81a1c1">[]</span> +</span></span><span style="display:flex;"><span> traverse f <span style="color:#eceff4">(</span>x<span style="color:#81a1c1">:</span>xs<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> fmap <span style="color:#eceff4">(</span><span style="color:#81a1c1">:[]</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">(</span>f x<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>Now we have an implementation that type checks, but it is still wrong, +since it doesn&rsquo;t satisfy the rule that <em>a traversal must not change the +shape of the structure it is traversing</em>, and here we are just dropping +the rest of the list. We need to find a way to use recursion and somehow +combine the results.</p> +<p>By looking at the type of <code>traverse :: (a -&gt; f b) -&gt; t a -&gt; f (t b)</code>, or +in our case specifically <code>traverse :: (a -&gt; f b) -&gt; [a] -&gt; f [b]</code> we can +see that using <code>traverse</code> recursively on the tail of the list would give +us the type we need.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Traversable</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> traverse <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">=</span> pure <span style="color:#81a1c1">[]</span> +</span></span><span style="display:flex;"><span> traverse f <span style="color:#eceff4">(</span>x<span style="color:#81a1c1">:</span>xs<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#eceff4">(</span>f x<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">_</span> traverse f xs +</span></span></code></pre></div><p>Now we have two values, one of type <code>f b</code> and one of type <code>f [b]</code>, which +are basically the head and the tail of the list, both wrapped in an +<code>Applicative</code> context. We also have a function <code>(:) :: a -&gt; [a] -&gt; [a]</code>, +which concatenates a head and a tail together into a single list.</p> +<p>Knowing all of this it just comes down to a basic use of <code>Applicative</code> +where we have a function of two arguments and need to apply it to two +values in the <code>Applicative</code> context. We can do this in two different +ways.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Traversable</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> traverse <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">=</span> pure <span style="color:#81a1c1">[]</span> +</span></span><span style="display:flex;"><span> traverse f <span style="color:#eceff4">(</span>x<span style="color:#81a1c1">:</span>xs<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> f x <span style="color:#81a1c1">&lt;*&gt;</span> traverse f xs +</span></span></code></pre></div><p>And an alternative definition using <code>liftA2</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Traversable</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> traverse <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">=</span> pure <span style="color:#81a1c1">[]</span> +</span></span><span style="display:flex;"><span> traverse f <span style="color:#eceff4">(</span>x<span style="color:#81a1c1">:</span>xs<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> liftA2 <span style="color:#eceff4">(</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">(</span>f x<span style="color:#eceff4">)</span> <span style="color:#eceff4">(</span>traverse f xs<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>It should be pretty clear now that we need the <code>Applicative</code> to be able +to actually implement <code>traverse</code>. If all we had was a <code>Functor</code> we +wouldn&rsquo;t be able to combine the <code>f b</code> and <code>f [b]</code> together.</p> +<h2 id="sequencea">sequenceA</h2> +<p>Now that we have <code>traverse</code> we can move on to define <code>sequenceA</code>. Here&rsquo;s +a specific type for our list instance.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">sequenceA</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Applicative</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">[</span>f a<span style="color:#eceff4">]</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">[</span>a<span style="color:#eceff4">]</span> +</span></span></code></pre></div><p>If you&rsquo;re familiar with <code>sequence :: Monad m =&gt; [m a] -&gt; m [a]</code> from +<code>Control.Monad</code> then you can see how these two functions are doing the +same thing. It simply takes the <code>Applicative</code> effects, runs them and +pulls them out of the list.</p> +<p>The implementation is really simple. Starting out with an empty list, we +just need to wrap it in the <code>Applicative</code> context.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">sequenceA</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">=</span> pure <span style="color:#81a1c1">[]</span> +</span></span></code></pre></div><p>Next comes the actual recursive implementaiton. If we pattern match on +the head and the tail of the list, we&rsquo;ll yet again get <code>f a</code> and <code>[f a]</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">sequenceA</span> <span style="color:#eceff4">(</span>x<span style="color:#81a1c1">:</span>xs<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> +</span></span></code></pre></div><p>We can call <code>sequenceA</code> recursively on the tail to get <code>f [a]</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">sequenceA</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">=</span> pure <span style="color:#81a1c1">[]</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">sequenceA</span> <span style="color:#eceff4">(</span>x<span style="color:#81a1c1">:</span>xs<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> sequenceA xs +</span></span></code></pre></div><p>But of course this isn&rsquo;t good enough. We need a way to combine the head +and the tail while they&rsquo;re both wrapped in an <code>Applicative</code> context. +This can be done in the same way as we did previously with <code>traverse</code>, +using <code>(:)</code> and the <code>Applicative</code> functions <code>&lt;$&gt;</code> and <code>&lt;*&gt;</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">sequenceA</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">=</span> pure <span style="color:#81a1c1">[]</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">sequenceA</span> <span style="color:#eceff4">(</span>x<span style="color:#81a1c1">:</span>xs<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> x <span style="color:#81a1c1">&lt;*&gt;</span> sequenceA xs +</span></span></code></pre></div><p>Or alternatively using <code>liftA2</code> again.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">sequenceA</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">=</span> pure <span style="color:#81a1c1">[]</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">sequenceA</span> <span style="color:#eceff4">(</span>x<span style="color:#81a1c1">:</span>xs<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> liftA2 <span style="color:#eceff4">(</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> x <span style="color:#eceff4">(</span>sequenceA xs<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>That&rsquo;s it, we have a working implementation for <code>sequenceA</code>.</p> +<h2 id="implementing-sequencea-with-traverse-and-vice-versa">Implementing sequenceA with traverse and vice versa</h2> +<p>If we now look at our implementations for <code>traverse</code> and <code>sequenceA</code> we +can definitely see some similarity there.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">traverse</span> <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">=</span> pure <span style="color:#81a1c1">[]</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">traverse</span> f <span style="color:#eceff4">(</span>x<span style="color:#81a1c1">:</span>xs<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> f x <span style="color:#81a1c1">&lt;*&gt;</span> traverse f xs +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">sequenceA</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">=</span> pure <span style="color:#81a1c1">[]</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">sequenceA</span> <span style="color:#eceff4">(</span>x<span style="color:#81a1c1">:</span>xs<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">:</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;$&gt;</span> x <span style="color:#81a1c1">&lt;*&gt;</span> sequenceA xs +</span></span></code></pre></div><p>The only difference is that <code>traverse</code> takes a function and applies it +to the head of the list, while <code>sequenceA</code> simply uses the head as it +is. Knowing this we can actually define <code>sequenceA</code> using <code>traverse</code> and +the <code>id</code> function.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">sequenceA</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Traversable</span> t<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Applicative</span> f<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> t <span style="color:#eceff4">(</span>f a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>t a<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">sequenceA</span> xs <span style="color:#81a1c1;font-weight:bold">=</span> traverse id xs +</span></span></code></pre></div><p>Could we do the same thing the other way around though? Yes! We most +certainly can define <code>traverse</code> by using <code>sequenceA</code> and the fact that +every <code>Traversable</code> is also a <code>Functor</code>. Let&rsquo;s take this step by step.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">traverse</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Traversable</span> t<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Applicative</span> f<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>t b<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">traverse</span> f xs <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> +</span></span></code></pre></div><p>We only have one way of applying our function <code>a -&gt; f b</code> to the <code>t a</code> +and that is using <code>fmap</code>, which would give us <code>t (f b)</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">traverse</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Traversable</span> t<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Applicative</span> f<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>t b<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">traverse</span> f xs <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1">$</span> fmap f xs +</span></span></code></pre></div><p>Now we&rsquo;ll get an error saying that we need a function <code>t (f b) -&gt; f (t b)</code>, which is exactly what <code>sequenceA</code> does!</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">traverse</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Traversable</span> t<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Applicative</span> f<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>t b<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">traverse</span> f xs <span style="color:#81a1c1;font-weight:bold">=</span> sequenceA <span style="color:#81a1c1">$</span> fmap f xs +</span></span></code></pre></div><h2 id="traversable-with-default-implementations">Traversable with default implementations</h2> +<p>Given the two implementations we just got we can rewrite our initial +<code>Traversable</code> type class to use those as a default implementation for +both functions.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">class</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Functor</span> t<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Foldable</span> t<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#81a1c1">Traversable</span> t <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> traverse <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Applicative</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>t b<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> traverse f xs <span style="color:#81a1c1;font-weight:bold">=</span> sequenceA <span style="color:#81a1c1">$</span> fmap f xs +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> sequenceA <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Applicative</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> t <span style="color:#eceff4">(</span>f a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>t a<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> sequenceA xs <span style="color:#81a1c1;font-weight:bold">=</span> traverse id xs +</span></span></code></pre></div><p>This is actually how it&rsquo;s done in the <code>Data.Traversable</code> module, except +that if you look at the source code you&rsquo;ll see the functions defined in +point free style.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">class</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Functor</span> t<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Foldable</span> t<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#81a1c1">Traversable</span> t <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> traverse <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Applicative</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>t b<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> traverse f <span style="color:#81a1c1;font-weight:bold">=</span> sequenceA <span style="color:#81a1c1">.</span> fmap f +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> sequenceA <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Applicative</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> t <span style="color:#eceff4">(</span>f a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>t a<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> sequenceA <span style="color:#81a1c1;font-weight:bold">=</span> traverse id +</span></span></code></pre></div><h2 id="default-implementation-for-functor-and-foldable-using-traversable">Default implementation for Functor and Foldable using Traversable</h2> +<p>It might not be so obvious at first, but a <code>Traversable</code> is a very +powerful concept. So powerful that it actually allows us to define both +<code>Functor</code> and <code>Foldable</code> if we have just a single function from +<code>Traversable</code>. The <code>Data.Traversable</code> module defines two functions, +<code>fmapDefault</code> and <code>foldMapDefault</code>, which can be used as an +implementation for <code>fmap</code> and <code>foldMap</code> if we so desire.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">fmapDefault</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Traversable</span> t <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t b +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">foldMapDefault</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Traversable</span> t<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Monoid</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m +</span></span></code></pre></div><p>The way we&rsquo;re going to implement these is very similar to what we did in +<a href="https://blog.jakuba.net/2014/07/14/lens-tutorial-introduction-part-1.html">the Lens introduction article</a>. +If this section is too hard for you to understand I recommend reading +the Lens article first and then come back here. Everything will make a +lot more sense.</p> +<p>Let&rsquo;s first compare the types of <code>traverse</code> and <code>fmap</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">fmap</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Functor</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f b +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">traverse</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Traversable</span> t<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Applicative</span> f<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>t b<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>The difference is that the function passed to <code>traverse</code> returns a value +wrapped in <code>Applicative</code> context, and the result is also wrapped. If we +could find a way to wrap the value after we apply the function, and then +unwrap it at the end, we would get exactly the same type as <code>fmap</code>.</p> +<p>We can use the <code>Identity</code> functor to do this, which defines a way to +unwrap it using <code>runIdentity :: Identity a -&gt; a</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">fmapDefault</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Traversable</span> t <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t b +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">fmapDefault</span> f x <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> +</span></span></code></pre></div><p>We don&rsquo;t have that many options here. To be able to give the function +<code>f</code> to a <code>traverse</code> we need to change it&rsquo;s type from <code>a -&gt; f a</code>. That&rsquo;s +where <code>Identity</code> comes in.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">fmapDefault</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Traversable</span> t <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t b +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">fmapDefault</span> f x <span style="color:#81a1c1;font-weight:bold">=</span> traverse <span style="color:#eceff4">(</span><span style="color:#81a1c1">Identity</span> <span style="color:#81a1c1">.</span> f<span style="color:#eceff4">)</span> x +</span></span></code></pre></div><p>Now our types don&rsquo;t align, since we are supposed to return <code>t b</code> but we +are returning <code>Identity (t b)</code>. The solution here is the above mentioned +<code>runIdentity</code> which simply unwraps the value.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">fmapDefault</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Traversable</span> t <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t b +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">fmapDefault</span> f x <span style="color:#81a1c1;font-weight:bold">=</span> runIdentity <span style="color:#81a1c1">$</span> traverse <span style="color:#eceff4">(</span><span style="color:#81a1c1">Identity</span> <span style="color:#81a1c1">.</span> f<span style="color:#eceff4">)</span> x +</span></span></code></pre></div><p>And once more in point free style.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">fmapDefault</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Traversable</span> t <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t b +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">fmapDefault</span> f <span style="color:#81a1c1;font-weight:bold">=</span> runIdentity <span style="color:#81a1c1">.</span> traverse <span style="color:#eceff4">(</span><span style="color:#81a1c1">Identity</span> <span style="color:#81a1c1">.</span> f<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>Compare this to the definition of <code>over</code> and you can see how it <em>looks +and feels</em> almost exactly the same.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">over</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">over</span> ln f <span style="color:#81a1c1;font-weight:bold">=</span> runIdentity <span style="color:#81a1c1">.</span> ln <span style="color:#eceff4">(</span><span style="color:#81a1c1">Identity</span> <span style="color:#81a1c1">.</span> f<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>We&rsquo;ll explain how this relates to Lenses in more detail in a followup +article, but for now let&rsquo;s move on to <code>foldMapDefault</code>.</p> +<h2 id="implementing-foldmapdefault">Implementing foldMapDefault</h2> +<p>This part is very hard to understand, so be careful.</p> +<p>If we compare the type of <code>foldMapDefault</code> with <code>traverse</code> we can yet +again see some similarity.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">foldMapDefault</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Traversable</span> t<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Monoid</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">traverse</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Traversable</span> t<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Applicative</span> f<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>t b<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>The difference from <code>fmapDefault</code> is that now we need a way to convert +each element of the <code>Traversable</code> to a <code>Monoid</code>.</p> +<p>We will use the <code>Const</code> applicative here, which as it so happens also +defines a <code>Monoid</code> instance.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">foldMapDefault</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Traversable</span> t<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Monoid</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">foldMapDefault</span> f x <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> +</span></span></code></pre></div><p>As previously we can only use <code>traverse</code> together with a function <code>a -&gt; f b</code>, but we have <code>a -&gt; m</code>, where by using <code>Const</code> we can do the <code>m -&gt; f b</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">foldMapDefault</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Traversable</span> t<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Monoid</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">foldMapDefault</span> f x <span style="color:#81a1c1;font-weight:bold">=</span> traverse <span style="color:#eceff4">(</span><span style="color:#81a1c1">Const</span> <span style="color:#81a1c1">.</span> f<span style="color:#eceff4">)</span> x +</span></span></code></pre></div><p>Again we&rsquo;re faced with the problem of having <code>Const m (t b)</code> instead of +<code>m</code>, which can be solved using <code>getConst</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">foldMapDefault</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Traversable</span> t<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Monoid</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">foldMapDefault</span> f x <span style="color:#81a1c1;font-weight:bold">=</span> getConst <span style="color:#81a1c1">$</span> traverse <span style="color:#eceff4">(</span><span style="color:#81a1c1">Const</span> <span style="color:#81a1c1">.</span> f<span style="color:#eceff4">)</span> x +</span></span></code></pre></div><p>And a point free version.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">foldMapDefault</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Traversable</span> t<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Monoid</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> t a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">foldMapDefault</span> f <span style="color:#81a1c1;font-weight:bold">=</span> getConst <span style="color:#81a1c1">.</span> traverse <span style="color:#eceff4">(</span><span style="color:#81a1c1">Const</span> <span style="color:#81a1c1">.</span> f<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>This is also very similar to one of the functions Lens provides, in +particular <code>view</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">view</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">view</span> ln <span style="color:#81a1c1;font-weight:bold">=</span> getConst <span style="color:#81a1c1">.</span> ln <span style="color:#81a1c1">Const</span> +</span></span></code></pre></div><h2 id="implementing-functor-and-foldable-with-traversable">Implementing Functor and Foldable with Traversable</h2> +<p>Now that we understand how both <code>fmapDefault</code> and <code>foldMapDefault</code> work, +we can use them to define a <code>Functor</code> and a <code>Foldable</code> instance for any +<code>Traversable</code> we might have.</p> +<p>We can test this out by defining a simple list type.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">List</span> a <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Nil</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">|</span> <span style="color:#81a1c1">Cons</span> a <span style="color:#eceff4">(</span><span style="color:#81a1c1">List</span> a<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">deriving</span> <span style="color:#81a1c1">Show</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Functor</span> <span style="color:#81a1c1">List</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> fmap <span style="color:#81a1c1;font-weight:bold">=</span> fmapDefault +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Foldable</span> <span style="color:#81a1c1">List</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> foldMap <span style="color:#81a1c1;font-weight:bold">=</span> foldMapDefault +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Traversable</span> <span style="color:#81a1c1">List</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> traverse <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1">Nil</span> <span style="color:#81a1c1;font-weight:bold">=</span> pure <span style="color:#81a1c1">Nil</span> +</span></span><span style="display:flex;"><span> traverse f <span style="color:#eceff4">(</span><span style="color:#81a1c1">Cons</span> x xs<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> fmap <span style="color:#81a1c1">Cons</span> <span style="color:#eceff4">(</span>f x<span style="color:#eceff4">)</span> <span style="color:#81a1c1">&lt;*&gt;</span> traverse f xs +</span></span></code></pre></div><p>We used <code>fmap = fmapDefault</code> and <code>foldMap = foldMapDefault</code> to define +our <code>Functor</code> and <code>Foldable</code> instances, which is all made possible by +also having a <code>Traversable</code> instance. Let&rsquo;s test this out to make sure +it works!</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> traverse <span style="color:#eceff4">(</span><span style="color:#88c0d0">\</span>x <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Just</span> <span style="color:#eceff4">(</span>x <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">))</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Cons</span> <span style="color:#b48ead">1</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Cons</span> <span style="color:#b48ead">2</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Cons</span> <span style="color:#b48ead">3</span> <span style="color:#81a1c1">Nil</span><span style="color:#eceff4">)))</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Just</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Cons</span> <span style="color:#b48ead">2</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Cons</span> <span style="color:#b48ead">3</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Cons</span> <span style="color:#b48ead">4</span> <span style="color:#81a1c1">Nil</span><span style="color:#eceff4">)))</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> fold <span style="color:#eceff4">(</span><span style="color:#81a1c1">Cons</span> <span style="color:#a3be8c">&#34;hello&#34;</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Cons</span> <span style="color:#a3be8c">&#34;world&#34;</span> <span style="color:#81a1c1">Nil</span><span style="color:#eceff4">))</span> +</span></span><span style="display:flex;"><span><span style="color:#a3be8c">&#34;helloworld&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> fmap <span style="color:#eceff4">(</span><span style="color:#81a1c1">+</span><span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Cons</span> <span style="color:#b48ead">1</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Cons</span> <span style="color:#b48ead">2</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Cons</span> <span style="color:#b48ead">3</span> <span style="color:#81a1c1">Nil</span><span style="color:#eceff4">)))</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Cons</span> <span style="color:#b48ead">2</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Cons</span> <span style="color:#b48ead">3</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Cons</span> <span style="color:#b48ead">4</span> <span style="color:#81a1c1">Nil</span><span style="color:#eceff4">))</span> +</span></span></code></pre></div><p>It might be a surprising, but everything works as it is supposed +to.</p> + + + + + Building Monad Transformers - Part 1 + https://blog.jakuba.net/2014-07-22-building-monad-transformers-part-1/ + Tue, 22 Jul 2014 00:00:00 +0000 + + https://blog.jakuba.net/2014-07-22-building-monad-transformers-part-1/ + <p>In this article we&rsquo;ll focus on building our own monad transformers. +We&rsquo;ll start out with an example code and improve it by building a simple +wrapper over <code>IO (Maybe a)</code>.</p> +<p>The following example is really simple, but I&rsquo;m sure you can imagine +doing something similar in your own application. The <code>findById</code> method +is there just to simulate a database query that might not find a result.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">User</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">User</span> <span style="color:#81a1c1;font-weight:bold">deriving</span> <span style="color:#81a1c1">Show</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">findById</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Maybe</span> <span style="color:#81a1c1">User</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">findById</span> <span style="color:#b48ead">1</span> <span style="color:#81a1c1;font-weight:bold">=</span> return <span style="color:#81a1c1">$</span> <span style="color:#81a1c1">Just</span> <span style="color:#81a1c1">User</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">findById</span> <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1;font-weight:bold">=</span> return <span style="color:#81a1c1">Nothing</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">findUsers</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Maybe</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">User</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1">User</span><span style="color:#eceff4">))</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">findUsers</span> x y <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> muser1 <span style="color:#81a1c1;font-weight:bold">&lt;-</span> findById x +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">case</span> muser1 <span style="color:#81a1c1;font-weight:bold">of</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">Nothing</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> return <span style="color:#81a1c1">Nothing</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">Just</span> user1 <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> muser2 <span style="color:#81a1c1;font-weight:bold">&lt;-</span> findById y +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">case</span> muser2 <span style="color:#81a1c1;font-weight:bold">of</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">Nothing</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> return <span style="color:#81a1c1">Nothing</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">Just</span> user2 <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1">$</span> <span style="color:#81a1c1">Just</span> <span style="color:#eceff4">(</span>user1<span style="color:#eceff4">,</span> user2<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>While there&rsquo;s nothing bad about <code>case</code> statements with pattern matching +I&rsquo;m sure we can all agree that this approach can easily blow out of +proportions.</p> +<p>One solution that won&rsquo;t work all the time might be to fetch both of the users +at the same time, which would allow us to make use of the <code>Maybe</code> monad. If our +<code>findById</code> function didn&rsquo;t do any side effects, we could&rsquo;ve written this.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">findById</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Maybe</span> <span style="color:#81a1c1">User</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">findById</span> <span style="color:#b48ead">1</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Just</span> <span style="color:#81a1c1">User</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">findById</span> <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Nothing</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">loadUsers</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Maybe</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">User</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1">User</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">loadUsers</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> user1 <span style="color:#81a1c1;font-weight:bold">&lt;-</span> findById <span style="color:#b48ead">1</span> +</span></span><span style="display:flex;"><span> user2 <span style="color:#81a1c1;font-weight:bold">&lt;-</span> findById <span style="color:#b48ead">2</span> +</span></span><span style="display:flex;"><span> return <span style="color:#eceff4">(</span>user1<span style="color:#eceff4">,</span> user2<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>Because <code>Maybe</code> is implemented in a way that it stops evaluating when it hits +on <code>Nothing</code> we get the behavior we intended without pattern matching. If one of +our <code>findById</code> fails to return a user, the whole function will return a +<code>Nothing</code>.</p> +<p>Unfortunately the act of finding a user needs to reach out to the real world, +which forces the <code>IO</code> monad upon us, making this approach impossible. We +somehow need to be able to teach <code>IO</code> the notion of failure.</p> +<h2 id="wrapping-io-in-maybeio">Wrapping <code>IO</code> in <code>MaybeIO</code></h2> +<p>Let&rsquo;s introduce a new monad which will simply wrap our <code>IO</code> computations into a +<code>Maybe</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">MaybeIO</span> a <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#eceff4">{</span> runMaybeIO <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Maybe</span> a<span style="color:#eceff4">)</span> <span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>The next step is to make <code>MaybeIO</code> into a <code>Monad</code>, which will allow us to use +it inside a <code>do</code> block, but first things first. The next version of GHC (7.10) +will require every <code>Monad</code> to also be an <code>Applicative</code>, which also means that +every <code>Monad</code> must be a <code>Functor</code>. We&rsquo;ll follow this an start out with a +<code>Functor</code> instance.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Functor</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> fmap f m <span style="color:#81a1c1;font-weight:bold">=</span> undefined +</span></span></code></pre></div><p>We&rsquo;ll use type holes to hint us in while implementing these instances. First +let&rsquo;s recap the type of <code>fmap</code>, which is <code>(a -&gt; b) -&gt; f a -&gt; f b</code>, which means +we have a function <code>f :: a -&gt; b</code> and a functor value <code>m :: f a</code>, or +specifically <code>m :: MaybeIO a</code>.</p> +<p>Before we can do anything to the <code>m</code> we need to unwrap <code>MaybeIO</code> to get to the +insides. We&rsquo;ll use pattern matching to do that since it&rsquo;s more concise +than using <code>runMaybeIO</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Functor</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> fmap f <span style="color:#eceff4">(</span><span style="color:#81a1c1">MaybeIO</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> undefined +</span></span></code></pre></div><p>We only have two things available to us, the function <code>f :: a -&gt; b</code> +which only works on the type <code>a</code>, and the fact that both <code>Maybe</code> and +<code>IO</code> are also <code>Functor</code> instances, which means we can use <code>fmap</code> to +reach deep into the <code>Maybe (IO a)</code> to apply our function <code>f</code> to get the +result.</p> +<p>Here comes a little trick, since <code>fmap</code> can also be thought of as <code>(a -&gt; b) -&gt; (f a -&gt; f b)</code>. If we compose <code>fmap</code> with <code>fmap</code>, it gives us exactly what we +need, a way to reach two functors deep to apply a function.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t fmap<span style="color:#81a1c1">.</span>fmap +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Functor</span> f<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Functor</span> g<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>g a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>g b<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>Substituting our types we get the following.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">fmap</span><span style="color:#81a1c1">.</span>fmap <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Maybe</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Maybe</span> b<span style="color:#eceff4">))</span> +</span></span></code></pre></div><p>We are not there quite yet, let&rsquo;s see what happens if we use this +approach to implement the <code>Functor</code> instance.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Functor</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> fmap f <span style="color:#eceff4">(</span><span style="color:#81a1c1">MaybeIO</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#eceff4">(</span>fmap<span style="color:#81a1c1">.</span>fmap<span style="color:#eceff4">)</span> f m +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">-- Couldn&#39;t match type ‘Maybe’ with ‘MaybeIO’</span> +</span></span></code></pre></div><p>We&rsquo;re returning the wrong type! The original value passed in was <code>MaybeIO a</code> +and we&rsquo;re returning <code>IO (Maybe b)</code> instead of <code>MaybeIO b</code>. Let&rsquo;s add a type +hole to make this crystal clear.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Functor</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> fmap f <span style="color:#eceff4">(</span><span style="color:#81a1c1">MaybeIO</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1">$</span> <span style="color:#eceff4">(</span>fmap<span style="color:#81a1c1">.</span>fmap<span style="color:#eceff4">)</span> f m +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">-- Found hole ‘_’ with type: Maybe (IO b) -&gt; MaybeIO b</span> +</span></span></code></pre></div><p>Now remember how in the beginning we said we&rsquo;ll be wrapping the <code>IO (Maybe a)</code> +into a <code>MaybeIO</code>? We can do that using the constructor of <code>MaybeIO</code>!</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Functor</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> fmap f <span style="color:#eceff4">(</span><span style="color:#81a1c1">MaybeIO</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1">$</span> <span style="color:#eceff4">(</span>fmap<span style="color:#81a1c1">.</span>fmap<span style="color:#eceff4">)</span> f m +</span></span></code></pre></div><p>There you go, a <code>Functor</code> instance for <code>MaybeIO</code>.</p> +<h2 id="applicative-instance-for-maybeio"><code>Applicative</code> instance for <code>MaybeIO</code></h2> +<p>The next step is to implement an <code>Applicative</code> instance for our <code>MaybeIO</code> +wrapper. Here&rsquo;s how the <code>Applicative</code> class looks in case you forgot.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">class</span> <span style="color:#81a1c1">Applicative</span> m <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> pure <span style="color:#81a1c1;font-weight:bold">::</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m a +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">&lt;*&gt;</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">::</span> m <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m b +</span></span></code></pre></div><p>In terms of our <code>MaybeIO</code> the types would look as following.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">pure</span> <span style="color:#81a1c1;font-weight:bold">::</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">MaybeIO</span> a +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#81a1c1">&lt;*&gt;</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">MaybeIO</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">MaybeIO</span> b +</span></span></code></pre></div><p>Implementing <code>pure</code> is simple, we just need to wrap a given value into a +minimal context. Since both <code>Maybe</code> and <code>IO</code> are an instance of <code>Applicative</code>, +we can use their <code>pure</code> much as we used <code>fmap</code> when implementing the <code>Functor instance</code> (don&rsquo;t forget to import <code>Control.Applicative</code>.)</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Applicative</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> pure <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1">.</span> pure <span style="color:#81a1c1">.</span> pure +</span></span></code></pre></div><p>We could&rsquo;ve also written this more explicitly using <code>Just</code> instead of <code>pure</code> +for wrapping the value in a <code>Maybe</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Applicative</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> pure <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1">.</span> pure <span style="color:#81a1c1">.</span> <span style="color:#81a1c1">Just</span> +</span></span></code></pre></div><p>But moving on, now comes the hard part, implementing <code>&lt;*&gt;</code>. This is probably +the hardest part of the whole article, so don&rsquo;t worry if it seems a bit +complicated. First we need to pattern match to get rid of the <code>MaybeIO</code> +wrapper, and then we also need to wrap the value on the right hand side in the +last step.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Applicative</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> pure <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1">.</span> pure <span style="color:#81a1c1">.</span> <span style="color:#81a1c1">Just</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">MaybeIO</span> f <span style="color:#81a1c1">&lt;*&gt;</span> <span style="color:#81a1c1">MaybeIO</span> m <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1">$</span> <span style="color:#81a1c1;font-weight:bold">_</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">-- Found hole ‘_’ with type: IO (Maybe b)</span> +</span></span></code></pre></div><p>The type hole tells us that we need to somehow get to a <code>IO (Maybe b)</code> with the +given <code>IO (Maybe (a -&gt; b))</code> and <code>IO (Maybe a)</code>. This seems like a typical +<em>reach into a box/context and apply a function</em> kind of problem, and it is, but +we do need to do something which isn&rsquo;t so apparent at first.</p> +<p>Both <code>Maybe</code> and <code>IO</code> are an instance of <code>Applicative</code>, which means we need to +somehow use <code>&lt;*&gt;</code> to apply the boxed function to the boxed value (pardon me for +saying boxed here, but it just seems like the right analogy here.)</p> +<p>The problem is that we can only use <code>&lt;*&gt;</code> to apply a function nested one level +deep, since the type is <code>m (a -&gt; b) -&gt; m a -&gt; m b</code>. Knowing that <code>&lt;*&gt;</code> is a two +argument function, meaning we can&rsquo;t use simple <code>.</code>, we need to look into the +documentation for <code>Applicative</code> and find the function <code>liftA2</code>, works just like +<code>fmap</code> on functors, but for two argument functions.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t liftA2 +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Applicative</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b <span style="color:#81a1c1;font-weight:bold">-&gt;</span> c<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f b <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f c +</span></span></code></pre></div><p>If we combine these two together we do get exactly what we need, a function +which takes two arguments, where first one is a function nested in two +applicatives, and a value, and applies the function to that value.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t liftA2 <span style="color:#eceff4">(</span><span style="color:#81a1c1">&lt;*&gt;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Applicative</span> f<span style="color:#eceff4">,</span> <span style="color:#81a1c1">Applicative</span> g<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=&gt;</span> +</span></span><span style="display:flex;"><span> f <span style="color:#eceff4">(</span>g <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">))</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>g a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>g b<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>Let&rsquo;s substitute our types once again to see how this exactly matches to what +we need.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">liftA2</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">&lt;*&gt;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Maybe</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> b<span style="color:#eceff4">))</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Maybe</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Maybe</span> b<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>We already have both of the arguments of the correct types, which means we can +just apply the function to them and get our instance.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Applicative</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> pure <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1">.</span> pure <span style="color:#81a1c1">.</span> <span style="color:#81a1c1">Just</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">MaybeIO</span> f <span style="color:#81a1c1">&lt;*&gt;</span> <span style="color:#81a1c1">MaybeIO</span> m <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1">$</span> liftA2 <span style="color:#eceff4">(</span><span style="color:#81a1c1">&lt;*&gt;</span><span style="color:#eceff4">)</span> f m +</span></span></code></pre></div><p>In the next step we&rsquo;ll move onto implementing the <code>Monad</code> instance. Make sure +you understand what we&rsquo;ve done so far.</p> +<h2 id="monad-instance-for-maybeio"><code>Monad</code> instance for <code>MaybeIO</code></h2> +<p>Now comes the final step that we&rsquo;ve been waiting for, implementing a <code>Monad</code> +instance for our <code>MaybeIO</code> wrapper. As we did before, here&rsquo;s how the <code>Monad</code> +class looks.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">class</span> <span style="color:#81a1c1">Monad</span> m <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1;font-weight:bold">::</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m a +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">&gt;&gt;=</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">::</span> m a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m b +</span></span></code></pre></div><p>We can already see that <code>return</code> will be exactly the same as <code>pure</code> for our +<code>Applicative</code>, so let&rsquo;s do that first.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Monad</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1;font-weight:bold">=</span> pure +</span></span></code></pre></div><p>Next comes the implementation of <code>&gt;&gt;=</code> or <em>bind</em>. First the initial structure</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Monad</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1;font-weight:bold">=</span> pure +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">MaybeIO</span> m <span style="color:#81a1c1">&gt;&gt;=</span> f <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1">$</span> <span style="color:#81a1c1;font-weight:bold">_</span> +</span></span></code></pre></div><p>We have a value of type <code>m :: IO (Maybe a)</code> and a function that we need to +apply to the inner <code>a</code> which has a type <code>f :: a -&gt; MaybeIO b</code>. We can use <code>&gt;&gt;=</code> +to get to the value inside the <code>IO</code> monad.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Monad</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1;font-weight:bold">=</span> pure +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">MaybeIO</span> m <span style="color:#81a1c1">&gt;&gt;=</span> f <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1">$</span> m <span style="color:#81a1c1">&gt;&gt;=</span> <span style="color:#88c0d0">\</span>x <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1;font-weight:bold">_</span> +</span></span></code></pre></div><p>This leaves us with <code>x :: Maybe a</code>, which is just one pattern match away from +the final solution.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Monad</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1;font-weight:bold">=</span> pure +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">MaybeIO</span> m <span style="color:#81a1c1">&gt;&gt;=</span> f <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1">$</span> m <span style="color:#81a1c1">&gt;&gt;=</span> <span style="color:#88c0d0">\</span>x <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1;font-weight:bold">case</span> x <span style="color:#81a1c1;font-weight:bold">of</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">Nothing</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> return <span style="color:#81a1c1">$</span> <span style="color:#81a1c1">Nothing</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">Just</span> val <span style="color:#81a1c1;font-weight:bold">-&gt;</span> runMaybeIO <span style="color:#81a1c1">$</span> f val +</span></span></code></pre></div><p>A very important thing to note here is that in the case of <code>Just val</code> we +need to unwrap the <code>MaybeIO</code> using <code>runMaybeIO</code>. One might think that we +could instead write it like this.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Monad</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1;font-weight:bold">=</span> pure +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">MaybeIO</span> m <span style="color:#81a1c1">&gt;&gt;=</span> f <span style="color:#81a1c1;font-weight:bold">=</span> m <span style="color:#81a1c1">&gt;&gt;=</span> <span style="color:#88c0d0">\</span>x <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1;font-weight:bold">case</span> x <span style="color:#81a1c1;font-weight:bold">of</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">Nothing</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1">$</span> return <span style="color:#81a1c1">$</span> <span style="color:#81a1c1">Nothing</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">Just</span> val <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f val +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">-- Couldn&#39;t match type ‘IO’ with ‘MaybeIO’</span> +</span></span></code></pre></div><p>The problem here is that <code>m &gt;&gt;= \x -&gt; ...</code> must have a return value of +<code>IO</code>, but we&rsquo;re trying to return <code>MaybeIO</code>. This is why we need to +unwrap the result of <code>f val</code> and then wrap it again after doing <code>&gt;&gt;=</code>, +as we did in the previous example.</p> +<h2 id="using-maybeio-to-cleanup-our-initial-example">Using <code>MaybeIO</code> to cleanup our initial example</h2> +<p>We manage to build ourselves a monad which combines the effects of <code>IO</code> and +<code>Maybe</code> together, which means we can use it to represent <code>IO</code> computations +which can fail. This is perfect for our initial example which uses <code>findById :: Int -&gt; IO (Maybe User)</code>.</p> +<p>Since the type of our computation is <code>MaybeIO</code> we need to wrap the <code>findById</code> +function to make use of the monad instance for <code>MaybeIO</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">smartFindUsers</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">User</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1">User</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">smartFindUsers</span> x y <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> user1 <span style="color:#81a1c1;font-weight:bold">&lt;-</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1">$</span> findById x +</span></span><span style="display:flex;"><span> user2 <span style="color:#81a1c1;font-weight:bold">&lt;-</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1">$</span> findById y +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> return <span style="color:#eceff4">(</span>user1<span style="color:#eceff4">,</span> user2<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>We can even go one step further and keep the original return value of +<code>findUsers</code> <code>IO (Maybe (User, User))</code> by unwrapping the <code>MaybeIO</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">smartFindUsers</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Maybe</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">User</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1">User</span><span style="color:#eceff4">))</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">smartFindUsers</span> x y <span style="color:#81a1c1;font-weight:bold">=</span> runMaybeIO <span style="color:#81a1c1">$</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> user1 <span style="color:#81a1c1;font-weight:bold">&lt;-</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1">$</span> findById x +</span></span><span style="display:flex;"><span> user2 <span style="color:#81a1c1;font-weight:bold">&lt;-</span> <span style="color:#81a1c1">MaybeIO</span> <span style="color:#81a1c1">$</span> findById y +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> return <span style="color:#eceff4">(</span>user1<span style="color:#eceff4">,</span> user2<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>Now let&rsquo;s go ahead and test this in GHCi to make sure we didn&rsquo;t break anything.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> smartFindUsers <span style="color:#b48ead">1</span> <span style="color:#b48ead">1</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Just</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">User</span><span style="color:#eceff4">,</span><span style="color:#81a1c1">User</span><span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>Our new version works exactly the same as the old one, but without the +necessary error handling boilerplate. Much like monads allow you to capture +control flow patterns, you can use monad transformers to add additional control +flow to your existing monads without sacrificing readability of your code.</p> +<p>The next step is to make our <code>MaybeIO</code> into an actual transformer by swapping +<code>IO</code> for any <code>Monad</code>.</p> +<h2 id="generalizing-maybeio-to-maybet">Generalizing <code>MaybeIO</code> to <code>MaybeT</code></h2> +<p>The real monad transformers you&rsquo;ll encounter in the world of Haskell are a bit +more generic than the one we just implemented. Instead of hard-coding the <code>IO</code> +monad we&rsquo;ll pass it in as a type parameter, resulting in the following +definition of <code>MaybeT</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">newtype</span> <span style="color:#81a1c1">MaybeT</span> m a <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">MaybeT</span> <span style="color:#eceff4">{</span> runMaybeT <span style="color:#81a1c1;font-weight:bold">::</span> m <span style="color:#eceff4">(</span><span style="color:#81a1c1">Maybe</span> a<span style="color:#eceff4">)</span> <span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>There aren&rsquo;t any significant changes, we just introduced a new type parameter +which will be the monad we&rsquo;re wrapping. Since everything else remains almost +exactly the same, I&rsquo;ll just show the <code>Monad</code> implementation here.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">newtype</span> <span style="color:#81a1c1">MaybeT</span> m a <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">MaybeT</span> <span style="color:#eceff4">{</span> runMaybeT <span style="color:#81a1c1;font-weight:bold">::</span> m <span style="color:#eceff4">(</span><span style="color:#81a1c1">Maybe</span> a<span style="color:#eceff4">)</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Monad</span> m <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#81a1c1">Monad</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">MaybeT</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">MaybeT</span> <span style="color:#81a1c1">.</span> return <span style="color:#81a1c1">.</span> <span style="color:#81a1c1">Just</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">MaybeT</span> m <span style="color:#81a1c1">&gt;&gt;=</span> f <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">MaybeT</span> <span style="color:#81a1c1">$</span> <span style="color:#81a1c1;font-weight:bold">do</span> value <span style="color:#81a1c1;font-weight:bold">&lt;-</span> m +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">case</span> value <span style="color:#81a1c1;font-weight:bold">of</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">Nothing</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> return <span style="color:#81a1c1">Nothing</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">Just</span> x <span style="color:#81a1c1;font-weight:bold">-&gt;</span> runMaybeT <span style="color:#81a1c1">$</span> f x +</span></span></code></pre></div><p>The only notable thing here is that our type parameter <code>m</code> is restricted to be +a <code>Monad</code> as well, since we&rsquo;re only going to be wrapping monads.</p> +<p>Our <code>findUsers</code> function will be exactly the same, we&rsquo;ll just need to swap +<code>runMaybeIO</code> for <code>runMaybeT</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">transformerFindUsers</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Maybe</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">User</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1">User</span><span style="color:#eceff4">))</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">transformerFindUsers</span> x y <span style="color:#81a1c1;font-weight:bold">=</span> runMaybeT <span style="color:#81a1c1">$</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> user1 <span style="color:#81a1c1;font-weight:bold">&lt;-</span> <span style="color:#81a1c1">MaybeT</span> <span style="color:#81a1c1">$</span> findById x +</span></span><span style="display:flex;"><span> user2 <span style="color:#81a1c1;font-weight:bold">&lt;-</span> <span style="color:#81a1c1">MaybeT</span> <span style="color:#81a1c1">$</span> findById y +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> return <span style="color:#eceff4">(</span>user1<span style="color:#eceff4">,</span> user2<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>Just to make it crystal clear what&rsquo;s going on here, the function without using +<code>runMaybeT</code> would look as follows.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">wrappedFindUsers</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">MaybeT</span> <span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">User</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1">User</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">wrappedFindUsers</span> x y <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> user1 <span style="color:#81a1c1;font-weight:bold">&lt;-</span> <span style="color:#81a1c1">MaybeT</span> <span style="color:#81a1c1">$</span> findById x +</span></span><span style="display:flex;"><span> user2 <span style="color:#81a1c1;font-weight:bold">&lt;-</span> <span style="color:#81a1c1">MaybeT</span> <span style="color:#81a1c1">$</span> findById y +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> return <span style="color:#81a1c1">$</span> <span style="color:#81a1c1">Just</span> <span style="color:#eceff4">(</span>user1<span style="color:#eceff4">,</span> user2<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>We can even introduce a type alias to have something called <code>MaybeIO</code> using the +<code>MaybeT</code> transformer.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">type</span> <span style="color:#81a1c1">MaybeIO</span> a <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">MaybeT</span> <span style="color:#81a1c1">IO</span> a +</span></span></code></pre></div><p>This is actually how the well known monads such as <code>Reader</code>, <code>Writer</code> and +<code>State</code> are defined. They&rsquo;re just type synonyms for the respective transformers +using the <code>Identity</code> monad.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">type</span> <span style="color:#81a1c1">Reader</span> r <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">ReaderT</span> r <span style="color:#81a1c1">Identity</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">type</span> <span style="color:#81a1c1">Writer</span> w <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">WriterT</span> w <span style="color:#81a1c1">Identity</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">type</span> <span style="color:#81a1c1">State</span> s <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">StateT</span> s <span style="color:#81a1c1">Identity</span> +</span></span></code></pre></div><p>If you&rsquo;re interested in learning more about the <code>Identity</code> monad and how it can +be used in some more advanced settings, take a look at <a href="https://blog.jakuba.net/2014/07/14/lens-tutorial-introduction-part-1.html">my Introduction to +Lenses article</a> +where it&rsquo;s explained step by step in great detail.</p> +<p>This concludes the first article in the series on Monad Transformers. Next time +we&rsquo;ll take a look at how we can stack one transformer onto another and +introduce the <code>MonadTrans</code> and <code>MonadIO</code> type classes.</p> + + + + + Mutable State in Haskell + https://blog.jakuba.net/2014-07-20-mutable-state-in-haskell/ + Sun, 20 Jul 2014 00:00:00 +0000 + + https://blog.jakuba.net/2014-07-20-mutable-state-in-haskell/ + <p>Haskell is a purely functional language, which means there are no side-effects +and all variables are immutable. <!-- raw HTML omitted -->But as you probably know this isn&rsquo;t +completely true.<!-- raw HTML omitted --> <em>All variables are indeed immutable, but there +are ways to construct mutable references where we can change what the +reference points to.</em></p> +<p>Without side effects we wouldn&rsquo;t be able to do much, which is +why Haskell gives us the IO monad. In a similar manner we have many ways to +achieve mutable state in Haskell, let&rsquo;s take a look at them:</p> +<ul> +<li>IORef</li> +<li>STRef in the ST monad</li> +<li>MVar</li> +<li>TVar in Software Transactional Memory (STM)</li> +</ul> +<h2 id="ioref">IORef</h2> +<p>We all know that the IO monad allows us to do arbitrary effects in the real +world, so it probably comes as no surprise that it also allows us to create a +mutable reference to an type, called <code>IORef</code> (from <code>Data.IORef</code>.) There is not +much complicated about <code>IORef</code>, as it only takes a single type parameter, which +is the type it&rsquo;s going to contain.</p> +<p>Before we move into specifics it is important to note here that modifying the +<code>IORef</code> is no a pure operation, which means ever single operation on the +<code>IORef</code> will be inside the <code>IO</code> monad.</p> +<p>Let&rsquo;s take a look at some of the functions available for manipulating <code>IORef</code>s.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">IORef</span> a +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">newIORef</span> <span style="color:#81a1c1;font-weight:bold">::</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">IORef</span> a<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">readIORef</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IORef</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> a +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">writeIORef</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IORef</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">modifyIORef</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IORef</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span></code></pre></div><p>First thing you&rsquo;ll probably notice is that in order to create an <code>IORef</code> we +need to give it a value. <strong>An <code>IORef</code> must always contain a value of a given +type, it is impossible to create it empty</strong>. Here&rsquo;s a simple example.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">import</span> <span style="color:#8fbcbb">Data.IORef</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">main</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">main</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> ref <span style="color:#81a1c1;font-weight:bold">&lt;-</span> newIORef <span style="color:#eceff4">(</span><span style="color:#b48ead">0</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Int</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> modifyIORef ref <span style="color:#eceff4">(</span><span style="color:#81a1c1">+</span><span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> readIORef ref <span style="color:#81a1c1">&gt;&gt;=</span> print +</span></span></code></pre></div><p><em>I&rsquo;ve used <code>0 :: Int</code> instead of just <code>0</code> to make it explicit that we&rsquo;re using +<code>Int</code>s. If you don&rsquo;t do that it won&rsquo;t affect the program but you might get a +warning from the compiler.</em></p> +<p>There&rsquo;s not much really happening in this example, we just create a new +<code>IORef</code>, increase it&rsquo;s value by <code>1</code> and then print the result. While this is +nice it doesn&rsquo;t really show much, so let&rsquo;s make this more complicated.</p> +<p>A common pattern in Haskell is to take an immutable data structure and put it +inside a mutable reference, which basically gives you a mutable version of that +data structure (let&rsquo;s ignore the fact that there might be a more efficient way +to do this for now.) This will work because we can take any Haskell type and +put it into an <code>IORef</code>. Let&rsquo;s begin by using <code>Maybe Int</code> to represent a +<em>mutable box for an <code>Int</code> which can be empty</em>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">magic</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IORef</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Maybe</span> <span style="color:#81a1c1">Int</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">magic</span> ref <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> value <span style="color:#81a1c1;font-weight:bold">&lt;-</span> readIORef ref +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">case</span> value <span style="color:#81a1c1;font-weight:bold">of</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">Just</span> <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> return <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">Nothing</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> writeIORef ref <span style="color:#eceff4">(</span><span style="color:#81a1c1">Just</span> <span style="color:#b48ead">42</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">main</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">main</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> ref <span style="color:#81a1c1;font-weight:bold">&lt;-</span> newIORef <span style="color:#81a1c1">Nothing</span> +</span></span><span style="display:flex;"><span> magic ref +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> readIORef ref <span style="color:#81a1c1">&gt;&gt;=</span> print +</span></span></code></pre></div><p>First we define a function which takes a <code>IORef (Maybe Int)</code>, that is <em>a +mutable reference that maybe contains an <code>Int</code></em> and produces some side effects. +The implementation simply reads the <code>IORef</code> and do nothing if it already has a +value, but if it contains <code>Nothing</code> it will replace that value with <code>Just 42</code>. +Our <code>main</code> function then simply <code>print</code>s the contents of the <code>IORef</code>, which is +<code>Just 42</code>.</p> +<h2 id="in-place-bubble-sort-with-ioref">In-place bubble sort with <code>IORef</code></h2> +<p>If you&rsquo;ve read this far there&rsquo;s a fair chance that you know how bubble sort +works. The important thing about it is that it works in-place and modifies the +array it is sorting. Here&rsquo;s a simple implementation in Ruby.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">def</span> <span style="color:#88c0d0">bubble_sort</span><span style="color:#eceff4">(</span>list<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> list<span style="color:#81a1c1">.</span>each_index <span style="color:#81a1c1;font-weight:bold">do</span> <span style="color:#81a1c1">|</span>i<span style="color:#81a1c1">|</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">(</span>list<span style="color:#81a1c1">.</span>length <span style="color:#81a1c1">-</span> i <span style="color:#81a1c1">-</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span><span style="color:#81a1c1">.</span>times <span style="color:#81a1c1;font-weight:bold">do</span> <span style="color:#81a1c1">|</span>j<span style="color:#81a1c1">|</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> list<span style="color:#81a1c1">[</span>j<span style="color:#81a1c1">]</span> <span style="color:#81a1c1">&gt;</span> list<span style="color:#81a1c1">[</span>j <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#81a1c1">]</span> +</span></span><span style="display:flex;"><span> list<span style="color:#81a1c1">[</span>j<span style="color:#81a1c1">]</span><span style="color:#eceff4">,</span> list<span style="color:#81a1c1">[</span>j <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#81a1c1">]</span> <span style="color:#81a1c1">=</span> list<span style="color:#81a1c1">[</span>j <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#81a1c1">]</span><span style="color:#eceff4">,</span> list<span style="color:#81a1c1">[</span>j<span style="color:#81a1c1">]</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">end</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">end</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">end</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">end</span> +</span></span></code></pre></div><p>The key part being here is that we&rsquo;re swapping the elements of the list as we +iterate through it. This is something we can&rsquo;t do in pure Haskell, but we can +attempt to do this using <code>IORef</code>s.</p> +<p>We will use a simple Haskell list where each element is <code>IORef Int</code>, so that we +can move them around. The exact type will be <code>[IORef Int]</code>.</p> +<p><em>Disclaimer: I am aware that using a list, which is a linked list, is a +horribly inefficient implementation. The point of this article is however to +show how <code>IORef</code> can be used, not how to properly sort an array.</em></p> +<p>Our sorting function will accept a plain list of <code>Int</code>s, wrap them all in +<code>IORef</code>s, do the sorting in place, and unwrap the <code>IORef</code>s to return a list of +<code>Int</code>s again.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">bubbleSort</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">[</span><span style="color:#81a1c1">Int</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#eceff4">[</span><span style="color:#81a1c1">Int</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">bubbleSort</span> input <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">let</span> ln <span style="color:#81a1c1;font-weight:bold">=</span> length input +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> xs <span style="color:#81a1c1;font-weight:bold">&lt;-</span> mapM newIORef input +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> forM_ <span style="color:#eceff4">[</span><span style="color:#b48ead">0</span><span style="color:#81a1c1">..</span>ln <span style="color:#81a1c1">-</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1">$</span> <span style="color:#88c0d0">\</span><span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> forM_ <span style="color:#eceff4">[</span><span style="color:#b48ead">0</span><span style="color:#81a1c1">..</span>ln <span style="color:#81a1c1">-</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1">$</span> <span style="color:#88c0d0">\</span>j <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">let</span> ix <span style="color:#81a1c1;font-weight:bold">=</span> xs <span style="color:#81a1c1">!!</span> j +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">let</span> iy <span style="color:#81a1c1;font-weight:bold">=</span> xs <span style="color:#81a1c1">!!</span> <span style="color:#eceff4">(</span>j <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> x <span style="color:#81a1c1;font-weight:bold">&lt;-</span> readIORef ix +</span></span><span style="display:flex;"><span> y <span style="color:#81a1c1;font-weight:bold">&lt;-</span> readIORef iy +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> when <span style="color:#eceff4">(</span>x <span style="color:#81a1c1">&gt;</span> y<span style="color:#eceff4">)</span> <span style="color:#81a1c1">$</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> writeIORef ix y +</span></span><span style="display:flex;"><span> writeIORef iy x +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> mapM readIORef xs +</span></span></code></pre></div><p>Let&rsquo;s go through the code one step at a time. First we need to calculate the +length of the list being sorted and bind that to a variable.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">let</span> ln <span style="color:#81a1c1;font-weight:bold">=</span> length input +</span></span></code></pre></div><p>Next we wrap all of the items in the list inside an <code>IORef</code>. This will allow us +to do the sort in-place by swapping around the values of the references.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">xs</span> <span style="color:#81a1c1;font-weight:bold">&lt;-</span> mapM newIORef input +</span></span></code></pre></div><p>Let&rsquo;s examine the <code>mapM</code> here a little bit. The <code>newIORef</code> function has a type +of <code>a -&gt; IO (IORef a)</code>, if we try to partially apply it with <code>map</code>, we&rsquo;ll get +back the following.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t map newIORef +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">[</span>a<span style="color:#eceff4">]</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">[</span><span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">IORef</span> a<span style="color:#eceff4">)]</span> +</span></span></code></pre></div><p>This is not very useful for us, since we need a <code>[IORef a]</code>. Fortunately +Haskell provides a <code>sequence :: [IO a] -&gt; IO [a]</code> function which simply pulls +out the monadic effects from a list.</p> +<pre tabindex="0"><code>λ&gt; :t sequence . map newIORef +:: [a] -&gt; IO [IORef a] +</code></pre><p><code>mapM</code> is simply defined a shorthand for as <code>sequence . map</code>. There also exists +<code>forM</code> which is exactly like <code>mapM</code>, but the arguments are swapped around.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t mapM +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">mapM</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Monad</span> m <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">[</span>a<span style="color:#eceff4">]</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m <span style="color:#eceff4">[</span>b<span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t forM +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">forM</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Monad</span> m <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">[</span>a<span style="color:#eceff4">]</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m <span style="color:#eceff4">[</span>b<span style="color:#eceff4">]</span> +</span></span></code></pre></div><p>One last variant is <code>mapM_</code> and <code>forM_</code>, which the same as <code>mapM</code> and <code>forM</code>, +only their return value is discarded.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t mapM_ +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">mapM_</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Monad</span> m <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">[</span>a<span style="color:#eceff4">]</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t forM_ +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">forM_</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Monad</span> m <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">[</span>a<span style="color:#eceff4">]</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> m <span style="color:#81a1c1">()</span> +</span></span></code></pre></div><p>We chose <code>forM</code> because the function we pass in as an argument is quite long +and it just ends up being syntactically more pleasing, and because we only care +about the effects produced by the function we apply. <code>[0..ln - 2]</code> simply +allows us to call the function <code>length - 2</code> number of times.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">forM_</span> <span style="color:#eceff4">[</span><span style="color:#b48ead">0</span><span style="color:#81a1c1">..</span>ln <span style="color:#81a1c1">-</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1">$</span> <span style="color:#88c0d0">\</span><span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> forM_ <span style="color:#eceff4">[</span><span style="color:#b48ead">0</span><span style="color:#81a1c1">..</span>ln <span style="color:#81a1c1">-</span> <span style="color:#b48ead">2</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1">$</span> <span style="color:#88c0d0">\</span>j <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span></code></pre></div><p>Next we extract two items from the list, note that these have the type <code>IORef Int</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">let</span> ix <span style="color:#81a1c1;font-weight:bold">=</span> xs <span style="color:#81a1c1">!!</span> j +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">let</span> iy <span style="color:#81a1c1;font-weight:bold">=</span> xs <span style="color:#81a1c1">!!</span> <span style="color:#eceff4">(</span>j <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>We need to read the values from the <code>IORef</code>s in order to be able to compare them</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">x</span> <span style="color:#81a1c1;font-weight:bold">&lt;-</span> readIORef ix +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">y</span> <span style="color:#81a1c1;font-weight:bold">&lt;-</span> readIORef iy +</span></span></code></pre></div><p>and then simply swap the contents if <code>x &gt; y</code></p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">when</span> <span style="color:#eceff4">(</span>x <span style="color:#81a1c1">&gt;</span> y<span style="color:#eceff4">)</span> <span style="color:#81a1c1">$</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> writeIORef ix y +</span></span><span style="display:flex;"><span> writeIORef iy x +</span></span></code></pre></div><p>The last step is to unwrap the <code>IORef</code>s.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">mapM</span> readIORef xs +</span></span></code></pre></div><p>Now that we went through each of the steps, let&rsquo;s test our bubble sort implementation.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> bubbleSort <span style="color:#eceff4">[</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">2</span><span style="color:#eceff4">,</span><span style="color:#b48ead">3</span><span style="color:#eceff4">,</span><span style="color:#b48ead">4</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">[</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">2</span><span style="color:#eceff4">,</span><span style="color:#b48ead">3</span><span style="color:#eceff4">,</span><span style="color:#b48ead">4</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> bubbleSort <span style="color:#eceff4">[</span><span style="color:#b48ead">4</span><span style="color:#eceff4">,</span><span style="color:#b48ead">3</span><span style="color:#eceff4">,</span><span style="color:#b48ead">2</span><span style="color:#eceff4">,</span><span style="color:#b48ead">1</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">[</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">2</span><span style="color:#eceff4">,</span><span style="color:#b48ead">3</span><span style="color:#eceff4">,</span><span style="color:#b48ead">4</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> bubbleSort <span style="color:#eceff4">[</span><span style="color:#b48ead">4</span><span style="color:#eceff4">,</span><span style="color:#b48ead">99</span><span style="color:#eceff4">,</span><span style="color:#b48ead">23</span><span style="color:#eceff4">,</span><span style="color:#b48ead">93</span><span style="color:#eceff4">,</span><span style="color:#b48ead">17</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">[</span><span style="color:#b48ead">4</span><span style="color:#eceff4">,</span><span style="color:#b48ead">17</span><span style="color:#eceff4">,</span><span style="color:#b48ead">23</span><span style="color:#eceff4">,</span><span style="color:#b48ead">93</span><span style="color:#eceff4">,</span><span style="color:#b48ead">99</span><span style="color:#eceff4">]</span> +</span></span></code></pre></div><p>It works! Keep in mind that this implementation is horribly slow. If you&rsquo;re +interested in fast arrays in Haskell <a href="http://hackage.haskell.org/package/vector">check out the vector +library</a>.</p> +<h2 id="st-monad">ST monad</h2> +<p>You&rsquo;ve probably noticed that the only reason why we need to perform our sorting +algorithm in the <code>IO</code> monad is to have mutable references, which is not ideal +since we&rsquo;re not really doing any <code>IO</code>.</p> +<p>Luckily for us there is a solution called the <em>state thread monad</em>. I won&rsquo;t be +going on into great detail since the API for <code>IORef</code> and <code>STRef</code> is almost +exactly the same.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">STRef</span> s a +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">newSTRef</span> <span style="color:#81a1c1;font-weight:bold">::</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">ST</span> s <span style="color:#eceff4">(</span><span style="color:#81a1c1">STRef</span> s a<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">readSTRef</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">STRef</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">ST</span> s a +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">writeSTRef</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">STRef</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">ST</span> s <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">modifySTRef</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">STRef</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">ST</span> s <span style="color:#81a1c1">()</span> +</span></span></code></pre></div><p>The key difference is that while we can&rsquo;t ever escape from the <code>IO</code> monad, we +do have the ability to escape from the <code>ST</code> monad with the <code>runST :: ST s a -&gt; a</code> function, making the computation pure.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">import</span> <span style="color:#8fbcbb">Control.Monad.ST</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">import</span> <span style="color:#8fbcbb">Data.STRef</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">magic</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Int</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">magic</span> x <span style="color:#81a1c1;font-weight:bold">=</span> runST <span style="color:#81a1c1">$</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> ref <span style="color:#81a1c1;font-weight:bold">&lt;-</span> newSTRef x +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> modifySTRef ref <span style="color:#eceff4">(</span><span style="color:#81a1c1">+</span><span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> readSTRef ref +</span></span></code></pre></div><p>The only thing worth mentioning here compared to the <code>IORef</code> example is that +the type of the function <code>magic</code> is just <code>Int -&gt; Int</code>, because we&rsquo;re able to +escape the <code>ST</code> monad using a call to <code>runST</code>.</p> +<p>If you&rsquo;re not sure why this is useful, think of the sorting algorithm we +developed earlier. There are many algorithms which require mutation, but which +are also pure in their nature. If the way to achieve mutation was using the +<code>IO</code> monad, we wouldn&rsquo;t be able to implement such algorithm in pure code.</p> +<h2 id="mvar">MVar</h2> +<p>The next type we&rsquo;re going to take a look at is a little bit more complicated +than <code>IORef</code>, it&rsquo;s called an <code>MVar</code>. As usual most of the API is similar, but +there is one huge difference. While an <code>IORef</code> must always have a value, <code>MVar</code> +can be empty.</p> +<p>We have two ways of constructing an <code>MVar</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">newMVar</span> <span style="color:#81a1c1;font-weight:bold">::</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">MVar</span> a<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">newEmptyMVar</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">MVar</span> a<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>We also have an additional operation <code>takeMVar :: MVar a -&gt; IO a</code> which takes a +value out of an <code>MVar</code> and leaves it empty. Now comes the important part, <strong>if +we try to do <code>takeMVar</code> from an empty <code>MVar</code>, it will block the thread until +someone else puts a value into the <code>MVar</code></strong>. The same thing happens when you +try to <code>putMVar</code> into an <code>MVar</code> that already has a value, it will block until +someone takes that value out.</p> +<p>Try compiling and running the following program.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">import</span> <span style="color:#8fbcbb">Control.Concurrent</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">main</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">main</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> a <span style="color:#81a1c1;font-weight:bold">&lt;-</span> newEmptyMVar +</span></span><span style="display:flex;"><span> takeMVar a +</span></span></code></pre></div><p>After a second or so you&rsquo;ll get an exception and the program will crash.</p> +<pre tabindex="0"><code>*** Exception: thread blocked indefinitely in an MVar operation +</code></pre><p>The reason for this is that there are no other threads that could possibly +modify the <code>MVar</code>, so the runtime kills the thread. If we modify the program to +first put a value into the <code>MVar</code> it will work correctly.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">main</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">main</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> a <span style="color:#81a1c1;font-weight:bold">&lt;-</span> newEmptyMVar +</span></span><span style="display:flex;"><span> putMVar a <span style="color:#a3be8c">&#34;hello&#34;</span> +</span></span><span style="display:flex;"><span> takeMVar a <span style="color:#81a1c1">&gt;&gt;=</span> print +</span></span></code></pre></div><p>Now you might be thinking, how does the runtime know that there are no other +threads that could put a value into that <code>MVar</code>? Using garbage collection!</p> +<p>Every <code>MVar</code> knows which threads are currently blocked on it. If a thread that +is currently blocked on an <code>MVar</code> is not accessible from any other running +thread, it will get killed since there is no way it to become unblocked.</p> +<p>If you&rsquo;re interested in more details about this I recommend reading the amazing +<a href="http://chimera.labs.oreilly.com/books/1230000000929/index.html">Parallel and Concurrent Programming in +Haskell</a> book, +specifically the <a href="http://chimera.labs.oreilly.com/books/1230000000929/ch15.html">chapter on how blocked <code>MVar</code>s are +handled</a>.</p> +<h2 id="synchronizing-threads-using-mvar">Synchronizing threads using <code>MVar</code></h2> +<p>One of the great benefits of <code>MVar</code>s is that they can be be used to serve as +synchronization primitives for communication between threads.</p> +<p>We can use them as a simple 1 item channel, where we fork a thread that forever +loops trying to read from the <code>MVar</code> and print the result, and in the main +thread we read input from the user and put it into the same <code>MVar</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">import</span> <span style="color:#8fbcbb">Control.Monad</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">import</span> <span style="color:#8fbcbb">Control.Concurrent</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">main</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">main</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> a <span style="color:#81a1c1;font-weight:bold">&lt;-</span> newEmptyMVar +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> forkIO <span style="color:#81a1c1">$</span> forever <span style="color:#81a1c1">$</span> takeMVar a <span style="color:#81a1c1">&gt;&gt;=</span> putStrLn +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> forever <span style="color:#81a1c1">$</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> text <span style="color:#81a1c1;font-weight:bold">&lt;-</span> getLine +</span></span><span style="display:flex;"><span> putMVar a text +</span></span></code></pre></div><p>Everything will work as expected since <code>takeMVar</code> will block until we put +something into the <code>MVar</code>.</p> +<p>One important thing to note here is that when <code>main</code> returns the runtime +automatically kills all of the other running threads. It doesn&rsquo;t wait for them +to finish. Let&rsquo;s see a simple example.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">import</span> <span style="color:#8fbcbb">Control.Monad</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">import</span> <span style="color:#8fbcbb">Control.Concurrent</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">main</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">main</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> forkIO <span style="color:#81a1c1">$</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> threadDelay <span style="color:#b48ead">2000000</span> +</span></span><span style="display:flex;"><span> putStrLn <span style="color:#a3be8c">&#34;Hello World&#34;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> putStrLn <span style="color:#a3be8c">&#34;Game over!&#34;</span> +</span></span></code></pre></div><p>If you run this using <code>runhaskell</code> or by compiling and running the binary +you&rsquo;ll only see the output of <code>Game over!</code>. The second thread will never print +<code>Hello World</code>, because by the time it starts waiting the <code>main</code> function will +return and the runtime will kill the other thread.</p> +<p>We can fix this by using an <code>MVar</code> to make the <code>main</code> function wait for the +other thread to finish.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">import</span> <span style="color:#8fbcbb">Control.Monad</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">import</span> <span style="color:#8fbcbb">Control.Concurrent</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">main</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">main</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> a <span style="color:#81a1c1;font-weight:bold">&lt;-</span> newEmptyMVar +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> forkIO <span style="color:#81a1c1">$</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> threadDelay <span style="color:#b48ead">2000000</span> +</span></span><span style="display:flex;"><span> putStrLn <span style="color:#a3be8c">&#34;Hello World&#34;</span> +</span></span><span style="display:flex;"><span> putMVar a <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> takeMVar a +</span></span><span style="display:flex;"><span> putStrLn <span style="color:#a3be8c">&#34;Game over!&#34;</span> +</span></span></code></pre></div><p>The main thread first tried to take a value out of the <code>MVar</code>, which will block +because there&rsquo;s nothing in there yet, and then the second thread will sleep for +2 seconds, print <code>Hello World</code> and put a <code>()</code> into the <code>MVar</code>. This causes +<code>main</code> to continue, print <code>Game over!</code> and exit the program. We could also do +this the other way around by using <code>putMVar</code> on a full <code>MVar</code> in order to +block, but the end result is the same.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">main</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">main</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> a <span style="color:#81a1c1;font-weight:bold">&lt;-</span> newMVar <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> forkIO <span style="color:#81a1c1">$</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> threadDelay <span style="color:#b48ead">2000000</span> +</span></span><span style="display:flex;"><span> putStrLn <span style="color:#a3be8c">&#34;Hello World&#34;</span> +</span></span><span style="display:flex;"><span> takeMVar a +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> putStrLn <span style="color:#a3be8c">&#34;Game over!&#34;</span> +</span></span><span style="display:flex;"><span> putMVar a <span style="color:#81a1c1">()</span> +</span></span></code></pre></div><p>There are many more things to cover with respect to <code>MVar</code>, but I&rsquo;m not going +to go more in depth here, since there already are other great resources on the +topic.</p> +<ul> +<li><a href="http://chimera.labs.oreilly.com/books/1230000000929/ch07.html">Parallel &amp; Concurrent Programming in Haskell - Chapter 7. Basic Concurrency: Threads and MVars</a></li> +<li><a href="http://book.realworldhaskell.org/read/concurrent-and-multicore-programming.html">Real World Haskell - Chapter 24. Concurrent and multicore programming</a></li> +</ul> +<h1 id="software-transactional-memory---stm">Software Transactional Memory - STM</h1> +<p>Last on our list is Software Transactional Memory. Much like we had <code>IORef</code> and +<code>MVar</code>, STM gives us <code>TVar</code>, which stands for <em>transaction variable</em>. The way +that STM works is that it builds up a log of actions that are to be performed +atomically. We won&rsquo;t be covering STM itself as a method for managing +concurrency, since it&rsquo;s a rather lengthy topic. Instead we&rsquo;ll just examine the +options for achieving mutable state using STM using a <code>TVar</code>.</p> +<p>Every STM operation happens inside the <code>STM</code> monad, which already tells us that +we can chain multiple <code>STM</code> operations into one (since the monad instance +provides us with <code>&gt;&gt;=</code>.) In order to run the actual <code>STM</code> transaction we must +use the function <code>atomically :: STM a -&gt; IO a</code>, which takes any <code>STM</code> operation +and performs it in a single atomic step.</p> +<p>The API for creating <code>TVar</code>s is almost the same as for <code>IORef</code>s.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">TVar</span> a +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">newTVar</span> <span style="color:#81a1c1;font-weight:bold">::</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">STM</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">TVar</span> a<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">readTVar</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">TVar</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">STM</span> a +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">writeTVar</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">TVar</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">STM</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">modifyTVar</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">TVar</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">STM</span> <span style="color:#81a1c1">()</span> +</span></span></code></pre></div><p>There are also alternatives that work in the <code>IO</code> monad.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">newTVarIO</span> <span style="color:#81a1c1;font-weight:bold">::</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">TVar</span> a<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">readTVarIO</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">TVar</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> a +</span></span></code></pre></div><p>Note that these are just convenience functions that we could have implemented +ourselves using <code>atomically</code> function.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">newTVarIO</span> <span style="color:#81a1c1;font-weight:bold">::</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">TVar</span> a<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">newTVarIO</span> <span style="color:#81a1c1;font-weight:bold">=</span> atomically <span style="color:#81a1c1">.</span> newTVar +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">readTVarIO</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">TVar</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> a +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">readTVarIO</span> <span style="color:#81a1c1;font-weight:bold">=</span> atomically <span style="color:#81a1c1">.</span> readTVar +</span></span></code></pre></div><p>Now let&rsquo;s move onto mutations. We&rsquo;ll use the same example as we did with +<code>IORef</code>, but implement it using a <code>TVar</code>. We have many ways to approach it, +either by building one big transaction with all the steps, or by doing this in +many small ones.</p> +<p>First let&rsquo;s do one big <code>atomically</code> with all the steps.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">bigTransaction</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">bigTransaction</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> value <span style="color:#81a1c1;font-weight:bold">&lt;-</span> atomically <span style="color:#81a1c1">$</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> var <span style="color:#81a1c1;font-weight:bold">&lt;-</span> newTVar <span style="color:#eceff4">(</span><span style="color:#b48ead">0</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Int</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> modifyTVar var <span style="color:#eceff4">(</span><span style="color:#81a1c1">+</span><span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> readTVar var +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> print value +</span></span></code></pre></div><p>There&rsquo;s not much interesting going on in here, so let&rsquo;s split it into smaller +chunks. Even though <code>modifyTVar</code> is the perfect function for our use case, we +can use a combination or <code>readTVar</code> and <code>writeTVar</code> to achieve the same, +because <code>atomically</code> will make sure those two happen in a single step.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">atomicReadWrite</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">atomicReadWrite</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> var <span style="color:#81a1c1;font-weight:bold">&lt;-</span> newTVarIO <span style="color:#eceff4">(</span><span style="color:#b48ead">0</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Int</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> atomically <span style="color:#81a1c1">$</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> value <span style="color:#81a1c1;font-weight:bold">&lt;-</span> readTVar var +</span></span><span style="display:flex;"><span> writeTVar var <span style="color:#eceff4">(</span>value <span style="color:#81a1c1">+</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> readTVarIO var <span style="color:#81a1c1">&gt;&gt;=</span> print +</span></span></code></pre></div><p>Since <code>STM</code> is a monad, we can also make this more interesting by combining two +<code>STM</code> operations together and running those atomically.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">f</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">TVar</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">STM</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">f</span> var <span style="color:#81a1c1;font-weight:bold">=</span> modifyTVar var <span style="color:#eceff4">(</span><span style="color:#81a1c1">+</span><span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">twoCombined</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">twoCombined</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> var <span style="color:#81a1c1;font-weight:bold">&lt;-</span> newTVarIO <span style="color:#eceff4">(</span><span style="color:#b48ead">0</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Int</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> atomically <span style="color:#81a1c1">$</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> f var +</span></span><span style="display:flex;"><span> f var +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> readTVarIO var <span style="color:#81a1c1">&gt;&gt;=</span> print +</span></span></code></pre></div><p>There&rsquo;s a lot more to <code>STM</code> than just <code>TVar</code>s which is why I&rsquo;d encourage you, +dear reader, to take a look at the following resources. You might find that it +will change the way you think about concurrent programming completely.</p> +<ul> +<li><a href="http://research.microsoft.com/en-us/um/people/simonpj/papers/stm/lock-free-flops06.pdf">Lock Free Data Structures using STM in Haskell</a></li> +<li><a href="http://chimera.labs.oreilly.com/books/1230000000929/ch10.html">Parallel and Concurrent Programming in Haskell - Chapter 10. Software Transactional Memory</a></li> +<li><a href="http://book.realworldhaskell.org/read/software-transactional-memory.html">Real World Haskell - Chapter 28. Software transactional memory</a></li> +</ul> + + + + + Lens Tutorial - Introduction (part 1) + https://blog.jakuba.net/2014-07-14-lens-tutorial-introduction-part-1/ + Mon, 14 Jul 2014 00:00:00 +0000 + + https://blog.jakuba.net/2014-07-14-lens-tutorial-introduction-part-1/ + <p>This article is the first in the upcoming series that aims to explain the +Haskell&rsquo;s <a href="http://hackage.haskell.org/package/lens"><code>lens</code> library</a> and the +ideas behind it in an approachable way. Don&rsquo;t worry if you&rsquo;re new to Haskell, +the only prerequisites here should be understanding of the <code>Functor</code> type +class, and understanding how records and algebraic data types work in Haskell.</p> +<p>We won&rsquo;t be using the <code>lens</code> library in this article yet. The API we&rsquo;ll develop +will be exactly the same, but for the sake of learning I&rsquo;ll try to show you how +everything works and why it works by re-implementing it from scratch.</p> +<p>Keep in mind that lenses are a very advanced topic in Haskell and it takes some +time to truly understand them. Don&rsquo;t worry if you don&rsquo;t understand everything +at first read.</p> +<h2 id="the-motivation-behind-lenses">The motivation behind lenses</h2> +<p>If you&rsquo;re coming from an imperative language like Ruby or Java, you&rsquo;re probably +used to seeing code like this:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>project<span style="color:#81a1c1">.</span>owner<span style="color:#81a1c1">.</span>name <span style="color:#81a1c1">=</span> <span style="color:#a3be8c">&#34;John&#34;</span> +</span></span></code></pre></div><p>The OOP people would call this <strong>a violation of the Law of Demeter</strong>, but let&rsquo;s +ignore that it&rsquo;s a bad practice for now. The question here is, can we achieve +something similar in Haskell?</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">User</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">User</span> <span style="color:#eceff4">{</span> name <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">String</span><span style="color:#eceff4">,</span> age <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Int</span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">deriving</span> <span style="color:#81a1c1">Show</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">Project</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Project</span> <span style="color:#eceff4">{</span> owner <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">User</span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">deriving</span> <span style="color:#81a1c1">Show</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">setOwnerName</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">String</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Project</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Project</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">setOwnerName</span> newName p <span style="color:#81a1c1;font-weight:bold">=</span> p <span style="color:#eceff4">{</span> owner <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#eceff4">(</span>owner p<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> name <span style="color:#81a1c1;font-weight:bold">=</span> newName <span style="color:#eceff4">}</span> <span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>Now we can already see how this is less than ideal. In order to change the name +of the <code>owner</code>, we need to re-assign the owner field in the <code>Project</code> with the +new <code>User</code>, which is updated using the record syntax. We could do this in +multiple steps as follows.</p> +<p>Code blocks with <code>λ&gt; </code> denote GHCi session.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1;font-weight:bold">let</span> bob <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">User</span> <span style="color:#eceff4">{</span> name <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#a3be8c">&#34;Bob&#34;</span><span style="color:#eceff4">,</span> age <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#b48ead">30</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1;font-weight:bold">let</span> project <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Project</span> <span style="color:#eceff4">{</span> owner <span style="color:#81a1c1;font-weight:bold">=</span> bob <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1;font-weight:bold">let</span> alice <span style="color:#81a1c1;font-weight:bold">=</span> bob <span style="color:#eceff4">{</span> name <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#a3be8c">&#34;Alice&#34;</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1;font-weight:bold">let</span> project2 <span style="color:#81a1c1;font-weight:bold">=</span> project <span style="color:#eceff4">{</span> owner <span style="color:#81a1c1;font-weight:bold">=</span> alice <span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>This is very tedious compared to the original Ruby example, especially since we +need to keep re-building the original structure as we go deeper and deeper.</p> +<h2 id="a-naive-lens-implementation">A naive lens implementation</h2> +<p>This is where lenses come to help you out. In essence, lenses are just getters +and setters which you can compose together. In a naive approach the type might +look something like the following:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">NaiveLens</span> s a <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">NaiveLens</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">{</span> view <span style="color:#81a1c1;font-weight:bold">::</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">,</span> set <span style="color:#81a1c1;font-weight:bold">::</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>Following the convention of <a href="http://lens.github.io/">the official lens library</a> +I&rsquo;ve named the type parameters <code>s</code> and <code>a</code>, where <code>s</code> is the <em>object</em> and <code>a</code> +is the <em>focus</em>. In our example above the <code>s</code> would be <code>Project</code> and <code>a</code> would +be a <code>String</code>, since we&rsquo;re trying to change the name of the project&rsquo;s user.</p> +<p>Now given a lens of type <code>NaiveLens User String</code> we can easily change the +name of a user</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1;font-weight:bold">let</span> john <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">User</span> <span style="color:#eceff4">{</span> name <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#a3be8c">&#34;John&#34;</span><span style="color:#eceff4">,</span> age <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#b48ead">30</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> set nameLens <span style="color:#a3be8c">&#34;Bob&#34;</span> john +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">User</span> <span style="color:#eceff4">{</span>name <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#a3be8c">&#34;Bob&#34;</span><span style="color:#eceff4">,</span> age <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#b48ead">30</span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>How is such lens implemented? It&rsquo;s simply a getter and a setter.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">nameLens</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">NaiveLens</span> <span style="color:#81a1c1">User</span> <span style="color:#81a1c1">String</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">nameLens</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">NaiveLens</span> name <span style="color:#eceff4">(</span><span style="color:#88c0d0">\</span>a s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#eceff4">{</span> name <span style="color:#81a1c1;font-weight:bold">=</span> a <span style="color:#eceff4">})</span> +</span></span></code></pre></div><p>The problem with this approach of sticking a getter and a setter into a data +type is that it doesn&rsquo;t scale very well. If we wanted to do something like +<em>increment the value at the target by one</em>, we would have to first <code>view</code> the +current value, apply +1 to it, and then <code>set</code> the new value. We could +encapsulate this by providing the lens with a third function call <code>over</code>:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">over</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s +</span></span></code></pre></div><p>We could use this similarly to <code>set</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1;font-weight:bold">let</span> john <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">User</span> <span style="color:#eceff4">{</span> name <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#a3be8c">&#34;John&#34;</span><span style="color:#eceff4">,</span> age <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#b48ead">30</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> over ageLens <span style="color:#eceff4">(</span><span style="color:#81a1c1">+</span><span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> john +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">User</span> <span style="color:#eceff4">{</span>name <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#a3be8c">&#34;John&#34;</span><span style="color:#eceff4">,</span> age <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#b48ead">31</span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">ageLens</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">NaiveLens</span> <span style="color:#81a1c1">User</span> <span style="color:#81a1c1">Int</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">ageLens</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">NaiveLens</span> age +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">(</span><span style="color:#88c0d0">\</span>a s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#eceff4">{</span> age <span style="color:#81a1c1;font-weight:bold">=</span> a <span style="color:#eceff4">})</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">(</span><span style="color:#88c0d0">\</span>f s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#eceff4">{</span> age <span style="color:#81a1c1;font-weight:bold">=</span> f <span style="color:#eceff4">(</span>age s<span style="color:#eceff4">)</span> <span style="color:#eceff4">})</span> +</span></span></code></pre></div><p>The problem is that now we need to provide a getter and two setters for each +lens, even if we just use one.</p> +<p>If you&rsquo;ve been using Haskell for a while you&rsquo;ve probably seen the magical +function <code>const</code>. It&rsquo;s actually not magical at all, it simply has a type of <code>a -&gt; b -&gt; a</code>, which allows us to turn <code>over :: (a -&gt; a) -&gt; s -&gt; s</code> into <code>set :: a -&gt; s -&gt; s</code> by partially applying it, which leads to the definition of <code>set</code> as +follows.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">set</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">NaiveLens</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">set</span> ln a s <span style="color:#81a1c1;font-weight:bold">=</span> over ln <span style="color:#eceff4">(</span>const a<span style="color:#eceff4">)</span> s +</span></span></code></pre></div><p>Here&rsquo;s how the whole code looks now</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">NaiveLens</span> s a <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">NaiveLens</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">{</span> view <span style="color:#81a1c1;font-weight:bold">::</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">,</span> over <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">set</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">NaiveLens</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">set</span> ln a s <span style="color:#81a1c1;font-weight:bold">=</span> over ln <span style="color:#eceff4">(</span>const a<span style="color:#eceff4">)</span> s +</span></span></code></pre></div><h2 id="lenses-with-side-effects-and-more">Lenses with side effects and more</h2> +<p>Now we can see that <code>over</code> is definitely useful, but what if our modifier +function needs to perform some side effects? For example we might want to send +the current value over the network to determine the new value. We could go on +as before and add yet another function called <code>overIO</code>, which would look as the +following:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">overIO</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> s +</span></span></code></pre></div><p>But this means our simple pair of a getter and a setter has grown into a getter +and two setters again. Not to mention that we might want to use <code>over</code> in more +settings than just <code>IO</code>. Here&rsquo;s how the type would look now.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">NaiveLens</span> s a <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">NaiveLens</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">{</span> view <span style="color:#81a1c1;font-weight:bold">::</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">,</span> over <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">,</span> overIO <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> s <span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>This is the point where the magical generalization of what is called the <em>van +Laarhoven lens</em> comes into play. First step is that we can write our <code>overIO</code> +in a more general way by swapping <code>IO</code> for a <code>Functor</code>, which gives us the +following type.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">overF</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Functor</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f s +</span></span></code></pre></div><p>For the sake of keeping this article short I&rsquo;m going to tell you that <code>overF</code> +is everything we need in order to implement <code>view</code>, <code>set</code>, <code>over</code> and <code>overIO</code>. +Which means we no longer need a <code>Lens</code> record type, since we&rsquo;ll have just one +function.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">type</span> <span style="color:#81a1c1">Lens</span> s a <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Functor</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f s +</span></span></code></pre></div><p>By making this a type alias instead of a <code>newtype</code> or <code>data</code> we get one amazing +property of lenses. You can define your own lenses without depending on the +<code>lens</code> library. <strong>Any function which has the appropriate type signature is a +lens</strong>, there is no magic.</p> +<p>One thing to note here is that we do need to enable the +<a href="http://www.haskell.org/haskellwiki/Rank-N_types"><code>RankNTypes</code></a> extension for +this type alias to compile. To do that simply add the following snippet to the +first line of your file.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">{-# LANGUAGE RankNTypes #-}</span> +</span></span></code></pre></div><p>or if you&rsquo;re following along in GHCi type <code>:set -XRankNTypes</code>. I won&rsquo;t be +explaining this in this article since it&rsquo;s quite a complicated topic, but if +you&rsquo;re interested in learning more, a simple google search will yield a lot of +good results.</p> +<hr> +<h2 id="implementing-over-set-and-view-in-terms-of-lens-s-a">Implementing <code>over</code>, <code>set</code> and <code>view</code> in terms of <code>Lens s a</code></h2> +<p>Let&rsquo;s summarize before we move on. We started with an idea that a lens +represents a getter and a setter into some data type. Then we generalized the +setter to work with functions (using <code>over</code>). Last we realized that <code>over</code> is +not good enough when we want to do side effects, so we moved to <code>overIO</code> and +finally generalized it to the <em>van Laarhoven</em> lens of <code>Functor f =&gt; (a -&gt; f a) -&gt; s -&gt; f s</code>.</p> +<p>So far I&rsquo;ve only told you that our new <code>Lens s a</code> can behave like <code>over</code>, <code>set</code> +and <code>view</code>, but we need to prove it to really understand why. In order to do +this we&rsquo;ll make use to two <code>Functor</code> instances that come from the <code>base</code> +library, namely <code>Data.Functor.Identity</code> and <code>Control.Applicative.Const</code>. Let&rsquo;s +start with the simplest one, that is implementing <code>over</code> with the <code>Identity</code> +functor.</p> +<h2 id="over-with-identity"><code>over</code> with <code>Identity</code></h2> +<p>First of all, here&rsquo;s the implementation of <code>Identity</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">newtype</span> <span style="color:#81a1c1">Identity</span> a <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Identity</span> <span style="color:#eceff4">{</span> runIdentity <span style="color:#81a1c1;font-weight:bold">::</span> a <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Functor</span> <span style="color:#81a1c1">Identity</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> fmap f <span style="color:#eceff4">(</span><span style="color:#81a1c1">Identity</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Identity</span> <span style="color:#eceff4">(</span>f a<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>The reason why this is useful is because we can put a value in, let it behave +as a functor, and then take the value out.</p> +<p>The final type of <code>over</code> that we&rsquo;re looking for is <code>over :: Lens s a -&gt; (a -&gt; a) -&gt; s -&gt; s</code>. We can read that as: <em>Given a lens focusing on an <code>a</code> inside of +an <code>s</code>, and a function from <code>a</code> to <code>a</code>, and an <code>s</code>, I can give you back a +modified <code>s</code> from applying the function to the focus point of the lens.</em></p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">over</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">over</span> ln f s <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> +</span></span></code></pre></div><blockquote> +<p>If you&rsquo;re on GHC 7.8.x you can copy the exact snippet above and get an error +telling you what type is needed in place of <code>_</code> (this functionality is provided +by so called type holes.) Also don&rsquo;t forget that you need to add the type alias +for <code>Lens s a</code> and enable the <code>RankNTypes</code> extension as mentioned above.</p> +</blockquote> +<p>We&rsquo;ll inline the <code>Lens</code> type synonym, just so that we can see what is really +going on. Don&rsquo;t worry if the type looks scary, it will all make sense in a +short while.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">over</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Functor</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f s<span style="color:#eceff4">))</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">over</span> ln f s <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> +</span></span></code></pre></div><p>I&rsquo;ve added a few parentheses, especially around the <code>s -&gt; f s</code>, to make it +clear as we go along with partial applications. Keep in mind that <code>Lens</code> is +just a function, nothing more.</p> +<p>We only have one function of the type <code>a -&gt; f a</code> available here to pass into +the lens <code>ln</code>, and that is <code>Identity</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">over</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">over</span> ln f s <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#eceff4">(</span>ln <span style="color:#81a1c1">Identity</span><span style="color:#eceff4">)</span> +</span></span></code></pre></div><h2 id="using-ghci-to-play-with-types">Using GHCi to play with types</h2> +<p>If you want to play along in GHCi, there&rsquo;s a neat little trick you can do to +interactively play with types. Say that you want to see the type of <code>ln Identity</code></p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1;font-weight:bold">let</span> ln <span style="color:#81a1c1;font-weight:bold">=</span> undefined <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Functor</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f s<span style="color:#eceff4">))</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t ln <span style="color:#81a1c1">Identity</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Identity</span> s +</span></span></code></pre></div><p>The reason why this works is because the <code>undefined</code> can take on any type. +Since we&rsquo;re just trying to make the types align, you won&rsquo;t get an error from +trying to evaluate the <code>undefined</code>, you&rsquo;ll just a type error. This way you can +keep trying to partially apply things to see if the types match as you expect.</p> +<p>Anyway, moving on. We haven&rsquo;t really used our function <code>f</code> yet, and there will +be no more <code>a</code> to apply it to ones we give something to the lens <code>ln</code>. This is +why we need to apply it before we stick in the <code>Identity</code>, or compose it with +the <code>Identity</code> to be specific.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">over</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">over</span> ln f s <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#eceff4">(</span>ln <span style="color:#eceff4">(</span><span style="color:#81a1c1">Identity</span> <span style="color:#81a1c1">.</span> f<span style="color:#eceff4">))</span> +</span></span></code></pre></div><p>Now our current type hole if <code>(s -&gt; f s) -&gt; s</code>, which means we can stick in our +<code>s</code>. To make this syntactically more pleasing we&rsquo;ll replace some parentheses +with <code>$</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">over</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">over</span> ln f s <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1">$</span> ln <span style="color:#eceff4">(</span><span style="color:#81a1c1">Identity</span> <span style="color:#81a1c1">.</span> f<span style="color:#eceff4">)</span> s +</span></span></code></pre></div><p>Hang in, we&rsquo;re almost done. The last thing we need do, as our type hole tells +us, is <code>f s -&gt; s</code>, which means we basically need to rip off the functor. This +is easy to do as we&rsquo;re using the <code>Identity</code> functor, so we just apply +<code>runIdentity</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">over</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">over</span> ln f s <span style="color:#81a1c1;font-weight:bold">=</span> runIdentity <span style="color:#81a1c1">$</span> ln <span style="color:#eceff4">(</span><span style="color:#81a1c1">Identity</span> <span style="color:#81a1c1">.</span> f<span style="color:#eceff4">)</span> s +</span></span></code></pre></div><p>If you&rsquo;re feeling adventurous, we can rewrite this using point free style.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">over</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">over</span> ln f <span style="color:#81a1c1;font-weight:bold">=</span> runIdentity <span style="color:#81a1c1">.</span> ln <span style="color:#eceff4">(</span><span style="color:#81a1c1">Identity</span> <span style="color:#81a1c1">.</span> f<span style="color:#eceff4">)</span> +</span></span></code></pre></div><h2 id="view-with-const"><code>view</code> with <code>Const</code></h2> +<p>Now let&rsquo;s move on to <code>view</code>, where the type is simply <code>view :: Lens s a -&gt; s -&gt; a</code>. We can read this as: <em>Given a lens that focuses on an <code>a</code> inside of an <code>s</code>, +and an <code>s</code>, I can give you an <code>a</code>.</em></p> +<p>This part is probably the most magical, since the type of the <code>Lens s a</code> is <code>(a -&gt; f a) -&gt; s -&gt; f s</code> and we&rsquo;re trying to implement something that&rsquo;s <code>s -&gt; a</code>, +which means we need to have a way to turn the final <code>f s</code> into an <code>a</code>. The key +to this is the <code>Const</code> functor.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">newtype</span> <span style="color:#81a1c1">Const</span> a b <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Const</span> <span style="color:#eceff4">{</span> getConst <span style="color:#81a1c1;font-weight:bold">::</span> a <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">instance</span> <span style="color:#81a1c1">Functor</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Const</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> fmap <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Const</span> a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Const</span> a +</span></span></code></pre></div><p>Let&rsquo;s break this down into steps and first explain how <code>Const</code> works. <code>Const</code> +is a wrapper which takes a value, hides it deep inside, and then pretends to be +a functor containing something else, which is why it ignores the function +you&rsquo;re trying to <code>fmap</code> over const. Here&rsquo;s an example:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t <span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;hello&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Const</span> <span style="color:#81a1c1">String</span> b +</span></span></code></pre></div><p>We&rsquo;ve hidden a <code>&quot;hello&quot;</code> string inside a <code>Const</code>, now let&rsquo;s try to apply a +boolean function to it using <code>fmap</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1;font-weight:bold">let</span> boolBox <span style="color:#81a1c1;font-weight:bold">=</span> fmap <span style="color:#eceff4">(</span><span style="color:#81a1c1">&amp;&amp;</span> <span style="color:#81a1c1">False</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Const</span> <span style="color:#a3be8c">&#34;hello&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t boolBox +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Const</span> <span style="color:#eceff4">[</span><span style="color:#81a1c1">Char</span><span style="color:#eceff4">]</span> <span style="color:#81a1c1">Bool</span> +</span></span></code></pre></div><p>The <code>Const</code> has taken over to be a type of <code>Const String Bool</code>. If we <code>fmap</code> +over a function <code>Bool -&gt; Double</code> we&rsquo;ll get a <code>Const String Double</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1">:</span>t fmap <span style="color:#eceff4">(</span><span style="color:#88c0d0">\</span><span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#b48ead">1.2</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Double</span><span style="color:#eceff4">)</span> boolBox +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Const</span> <span style="color:#81a1c1">String</span> <span style="color:#81a1c1">Double</span> +</span></span></code></pre></div><p>The important thing to keep in mind here is that the <code>Const</code> simply ignores the +function we&rsquo;re fmapping and takes on the new type, while keeping our original +<code>String</code> safe. We can extract it back at any time we want, no matter how many +things we&rsquo;ve <code>fmap</code>ped.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> getConst boolBox +</span></span><span style="display:flex;"><span><span style="color:#a3be8c">&#34;hello&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> getConst <span style="color:#81a1c1">$</span> fmap <span style="color:#eceff4">(</span><span style="color:#88c0d0">\</span><span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#b48ead">1.2</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Double</span><span style="color:#eceff4">)</span> boolBox +</span></span><span style="display:flex;"><span><span style="color:#a3be8c">&#34;hello&#34;</span> +</span></span></code></pre></div><h2 id="the-actual-view-implementation">The actual <code>view</code> implementation</h2> +<p>Let&rsquo;s do this using type holes again.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">view</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">view</span> ln s <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> +</span></span></code></pre></div><p>We can approach this the same way as we did before when implementing <code>over</code> +using <code>Identity</code>. First of all, here&rsquo;s the type of <code>Lens s a</code> again in case you +forgot <code>Functor f =&gt; (a -&gt; f a) -&gt; s -&gt; f s</code>.</p> +<p>If you squint hard enough you can see that if we somehow pass a function to +<code>ln</code>, we&rsquo;ll get back another function of the type <code>s -&gt; f s</code>, which we can give +our <code>s</code>, and then the only thing remaining is to extract the resulting <code>a</code> out +of the <code>f s</code>. Again the only function that fits here is <code>Const</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">view</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">view</span> ln s <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1">$</span> ln <span style="color:#81a1c1">Const</span> +</span></span></code></pre></div><p>The type of the hole here is <code>(s -&gt; f s) -&gt; a</code>, which means we can apply our +<code>s</code> on the right side as we did with <code>over</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">view</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">view</span> ln s <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1">$</span> ln <span style="color:#81a1c1">Const</span> s +</span></span></code></pre></div><p>Now all we&rsquo;re left with is <code>f s -&gt; a</code>, and because we know that the <code>f s</code> is +actually <code>Const a s</code> we can get back the <code>a</code> using <code>getConst</code></p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">view</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">view</span> ln s <span style="color:#81a1c1;font-weight:bold">=</span> getConst <span style="color:#81a1c1">$</span> ln <span style="color:#81a1c1">Const</span> s +</span></span></code></pre></div><p>And there you go, we got ourselves a <code>view</code>. I won&rsquo;t be showing how to +implement <code>set</code> step by step, since it can be trivially defined either in terms +of <code>over</code>, which is good enough for us.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">set</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> s a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">set</span> ln x <span style="color:#81a1c1;font-weight:bold">=</span> over ln <span style="color:#eceff4">(</span>const x<span style="color:#eceff4">)</span> +</span></span></code></pre></div><h2 id="writing-our-own-lenses">Writing our own lenses</h2> +<p>In order to use lenses we actually need to have some lenses. As said earlier, +we do not need the <code>lens</code> library to define a new lens, we only need a function +with the type of <code>Functor f =&gt; (a -&gt; f a) -&gt; s -&gt; f s</code>. Let&rsquo;s make one!</p> +<p>We&rsquo;ll start by implementing the <code>_1</code> lens, which focuses on a first element of +a pair. The type will be <code>Lens (a,b) a</code> or specifically <code>Functor f =&gt; (a -&gt; f a) -&gt; (a,b) -&gt; f (a,b)</code>, in another words <em>Given a pair of <code>(a,b)</code> the lens +focuses on the first element of the pair, which is <code>a</code></em>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">_1</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Functor</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a<span style="color:#eceff4">,</span>b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>a<span style="color:#eceff4">,</span>b<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">_1</span> f <span style="color:#eceff4">(</span>x<span style="color:#eceff4">,</span>y<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1;font-weight:bold">_</span> +</span></span></code></pre></div><p>An interesting thing about pure functions in Haskell is that more often than +not, there is only one way to implement a function so that it typechecks. We +can use the types as we did earlier to guide us while implementing this.</p> +<p>Ok let&rsquo;s get going. We have three values available (via the function +parameters), <code>f :: a -&gt; f a</code>, <code>x :: a</code> and <code>y :: b</code>. The only thing we can do +here is apply <code>f</code> to <code>x</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">_1</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Functor</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a<span style="color:#eceff4">,</span>b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>a<span style="color:#eceff4">,</span>b<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">_1</span> f <span style="color:#eceff4">(</span>x<span style="color:#eceff4">,</span>y<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> f x +</span></span></code></pre></div><p>This will fail to typecheck, since we&rsquo;re trying to return <code>f a</code> instead of <code>f (a,b)</code>. What else can we do now? We know <code>f</code> is a <code>Functor</code>, which means we can +use <code>fmap</code>. We also know that we need to somehow use <code>y</code> to compose the result. +If you think about this for a while, all we can really do is <code>fmap</code> some +function on the result of <code>f x</code></p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">_1</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Functor</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a<span style="color:#eceff4">,</span>b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>a<span style="color:#eceff4">,</span>b<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">_1</span> f <span style="color:#eceff4">(</span>x<span style="color:#eceff4">,</span>y<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> fmap <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#eceff4">(</span>f x<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>The result is that the type of <code>_</code> in this case must be <code>a -&gt; (a, b)</code>. That&rsquo;s +it, we only have one thing of type <code>b</code>, which is <code>y</code>, and the <code>a</code> we can take +just form the parameter passed to the lambda, hence giving us the following.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">_1</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Functor</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a<span style="color:#eceff4">,</span>b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span>a<span style="color:#eceff4">,</span>b<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">_1</span> f <span style="color:#eceff4">(</span>x<span style="color:#eceff4">,</span>y<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> fmap <span style="color:#eceff4">(</span><span style="color:#88c0d0">\</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span>a<span style="color:#eceff4">,</span> y<span style="color:#eceff4">))</span> <span style="color:#eceff4">(</span>f x<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>Whoa, did we just write an actual lens? I believe we did sir. Let&rsquo;s test things +out!</p> +<h2 id="using-lenses">Using lenses</h2> +<p>Now that we got ourselves a <code>view</code> and <code>_1</code> lens, let&rsquo;s play!</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> view _1 <span style="color:#eceff4">(</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">2</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#b48ead">1</span> +</span></span></code></pre></div><p>We can also use <code>set</code> and <code>over</code> to change the value</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> set _1 <span style="color:#b48ead">3</span> <span style="color:#eceff4">(</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">2</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#b48ead">3</span><span style="color:#eceff4">,</span><span style="color:#b48ead">2</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> over _1 <span style="color:#eceff4">(</span><span style="color:#81a1c1">+</span><span style="color:#b48ead">3</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">(</span><span style="color:#b48ead">1</span><span style="color:#eceff4">,</span><span style="color:#b48ead">2</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#b48ead">4</span><span style="color:#eceff4">,</span><span style="color:#b48ead">2</span><span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>Let&rsquo;s see how to define a lens for the original <code>User</code> and <code>Project</code> types.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">User</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">User</span> <span style="color:#eceff4">{</span> name <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">String</span><span style="color:#eceff4">,</span> age <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Int</span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">deriving</span> <span style="color:#81a1c1">Show</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">Project</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Project</span> <span style="color:#eceff4">{</span> owner <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">User</span> <span style="color:#eceff4">}</span> <span style="color:#81a1c1;font-weight:bold">deriving</span> <span style="color:#81a1c1">Show</span> +</span></span></code></pre></div><p>We&rsquo;ll start with a lens for the <code>User</code>&rsquo;s <code>name</code>, which simply has the type +<code>Lens User String</code>. There&rsquo;s no magic here, we&rsquo;ll just follow the same pattern +as we did with the <code>_1</code> lens.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">nameLens</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> <span style="color:#81a1c1">User</span> <span style="color:#81a1c1">String</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">nameLens</span> f user <span style="color:#81a1c1;font-weight:bold">=</span> fmap <span style="color:#eceff4">(</span><span style="color:#88c0d0">\</span>newName <span style="color:#81a1c1;font-weight:bold">-&gt;</span> user <span style="color:#eceff4">{</span> name <span style="color:#81a1c1;font-weight:bold">=</span> newName <span style="color:#eceff4">})</span> <span style="color:#eceff4">(</span>f <span style="color:#eceff4">(</span>name user<span style="color:#eceff4">))</span> +</span></span></code></pre></div><p>As you can see this is just mechanical work. We can define the other two lenses +for <code>age</code> and <code>owner</code> by simply copy pasting the first one and changing a few +things around.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">ageLens</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> <span style="color:#81a1c1">User</span> <span style="color:#81a1c1">Int</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">ageLens</span> f user <span style="color:#81a1c1;font-weight:bold">=</span> fmap <span style="color:#eceff4">(</span><span style="color:#88c0d0">\</span>newAge <span style="color:#81a1c1;font-weight:bold">-&gt;</span> user <span style="color:#eceff4">{</span> age <span style="color:#81a1c1;font-weight:bold">=</span> newAge <span style="color:#eceff4">})</span> <span style="color:#eceff4">(</span>f <span style="color:#eceff4">(</span>age user<span style="color:#eceff4">))</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">ownerLens</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> <span style="color:#81a1c1">Project</span> <span style="color:#81a1c1">User</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">ownerLens</span> f project <span style="color:#81a1c1;font-weight:bold">=</span> fmap <span style="color:#eceff4">(</span><span style="color:#88c0d0">\</span>newOwner <span style="color:#81a1c1;font-weight:bold">-&gt;</span> project <span style="color:#eceff4">{</span> owner <span style="color:#81a1c1;font-weight:bold">=</span> newOwner <span style="color:#eceff4">})</span> <span style="color:#eceff4">(</span>f <span style="color:#eceff4">(</span>owner project<span style="color:#eceff4">))</span> +</span></span></code></pre></div><h2 id="composing-lenses-together">Composing lenses together</h2> +<p>Because lenses are just functions (remember that <code>Lens s a</code> is just a type +alias) we can compose them using the ordinary function composition <code>.</code></p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">ownerNameLens</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Lens</span> <span style="color:#81a1c1">Project</span> <span style="color:#81a1c1">String</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">ownerNameLens</span> <span style="color:#81a1c1;font-weight:bold">=</span> ownerLens<span style="color:#81a1c1">.</span>nameLens +</span></span></code></pre></div><p>Let&rsquo;s test this out:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1;font-weight:bold">let</span> john <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">User</span> <span style="color:#eceff4">{</span> name <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#a3be8c">&#34;John&#34;</span><span style="color:#eceff4">,</span> age <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#b48ead">30</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> <span style="color:#81a1c1;font-weight:bold">let</span> p <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Project</span> <span style="color:#eceff4">{</span> owner <span style="color:#81a1c1;font-weight:bold">=</span> john <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> view ownerNameLens p +</span></span><span style="display:flex;"><span><span style="color:#a3be8c">&#34;John&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">λ</span><span style="color:#81a1c1">&gt;</span> set ownerNameLens <span style="color:#a3be8c">&#34;Bob&#34;</span> p +</span></span><span style="display:flex;"><span><span style="color:#81a1c1">Project</span> <span style="color:#eceff4">{</span>owner <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">User</span> <span style="color:#eceff4">{</span>name <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#a3be8c">&#34;Bob&#34;</span><span style="color:#eceff4">,</span> age <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#b48ead">30</span><span style="color:#eceff4">}}</span> +</span></span></code></pre></div><h2 id="conclusion-of-part-1">Conclusion of part 1</h2> +<p>Congratulations to you if you&rsquo;ve read this far, you now have a good +understanding of how the basic <code>Lens s a</code> works. This is not the end though, +since lenses are a very large subject and there is a lot of ground to cover. +The followup posts to this one will cover the more general <code>Lens s t a b</code> type, +folds, traversals, prisms, isos, using template haskell to generate lenses, and +much more!</p> +<p>If you&rsquo;re curious especially about the <code>Lens s t a b</code> type and what it means, +it&rsquo;s basically just a small generalization of what we&rsquo;ve devleoped here. +Compare the following two:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">type</span> <span style="color:#81a1c1">Lens&#39;</span> s a <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Functor</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f a<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f s +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">type</span> <span style="color:#81a1c1">Lens</span> s t a b <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Functor</span> f <span style="color:#81a1c1;font-weight:bold">=&gt;</span> <span style="color:#eceff4">(</span>a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f b<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> s <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f t +</span></span></code></pre></div><p>This might look weird at first, but it&rsquo;s not if you apply it to a specific data +type, such as:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1">Lens</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Int</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1">String</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Double</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1">String</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1">Int</span> <span style="color:#81a1c1">Double</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#81a1c1">Int</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#81a1c1">Double</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Int</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1">String</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> f <span style="color:#eceff4">(</span><span style="color:#81a1c1">Double</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1">String</span><span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>It simply allows you to change the type of the underlying structure, but as I +said earlier, we&rsquo;ll cover this more in one of the upcoming blog posts.</p> + + + + + Using Phantom Types in Haskell for Extra Safety - Part 2 + https://blog.jakuba.net/2014-07-10-using-phantom-types-in-haskell-for-extra-safety-part-2/ + Thu, 10 Jul 2014 00:00:00 +0000 + + https://blog.jakuba.net/2014-07-10-using-phantom-types-in-haskell-for-extra-safety-part-2/ + <p>I&rsquo;ve received <strong>a lot of reactions to the <a href="https://blog.jakuba.net/2014/07/08/using-phantom-types-for-extra-safety.html">previous blog post about Phantom +Types</a></strong> +over the past two days, which is why I&rsquo;ve decided to summarize what I&rsquo;ve +learned in another blog post.</p> +<p>First, here&rsquo;s a summarized problem from the previous post. We have a <code>Message</code> +which can be either <code>PlainText</code> or <code>Encrypted</code>. We&rsquo;ve used Phantom Types to +enforce this in the type system:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">Message</span> a <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">String</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">PlainText</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">Encrypted</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">send</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">Encrypted</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">encrypt</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">PlainText</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">Encrypted</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">decrypt</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">Encrypted</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">PlainText</span> +</span></span></code></pre></div><h2 id="can-newtype-do-the-same">Can newtype do the same?</h2> +<p>Many people mentioned that we could use the Haskell&rsquo;s <code>newtype</code> to do the same, +here&rsquo;s how that would look.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">String</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">newtype</span> <span style="color:#81a1c1">PlainTextMessage</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">PlainTextMessage</span> <span style="color:#81a1c1">Message</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">newtype</span> <span style="color:#81a1c1">EncryptedMessage</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">EncryptedMessage</span> <span style="color:#81a1c1">Message</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">send</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">EncryptedMessage</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">encrypt</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">PlainTextMessage</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">EncryptedMessage</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">decrypt</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">EncryptedMessage</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">PlainTextMessage</span> +</span></span></code></pre></div><p>This example would work perfectly fine, and it&rsquo;s how you&rsquo;d probably solve this +in a statically typed language with no option for representing Phantom Types.</p> +<p>But there&rsquo;s one downside to this solution. Our new <code>PlainTextMessage</code> and +<code>EncryptedMessage</code> are no longer related, which means we can&rsquo;t write a function +that operates on both of them. Why would we need that? I&rsquo;m glad you asked! +Here&rsquo;s how a simple <code>length</code> function would look in Haskell.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">length</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#eceff4">[</span>a<span style="color:#eceff4">]</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Int</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">length</span> <span style="color:#81a1c1">[]</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#b48ead">0</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">length</span> <span style="color:#eceff4">(</span>x<span style="color:#81a1c1">:</span>xs<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#b48ead">1</span> <span style="color:#81a1c1">+</span> length xs +</span></span></code></pre></div><p>In order to calculate the length of a list, we do not care what is in the list. +The same way if we wanted to calculate a <code>messageLength</code>, we don&rsquo;t care if the +message has been encrypted or not, we just want to count the characters. This +is dead simple if we had Phantom Types, but it would be very hard using the +<code>newtype</code> solution, since <code>PlainTextMessage</code> and <code>EncryptedMessage</code> are +parametrically (is that even a word?) not the same thing.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">messageLength</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Message</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Int</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">messageLength</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Message</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> length m +</span></span></code></pre></div><p>As you can see, we simply ignore the type parameter <code>a</code> of the <code>Message</code> type +and calculate the length of the inner <code>String</code>.</p> +<p>We could achieve the same in the <code>newtype</code> solution using type classes, but it +would be unnecessarily more complicated. Phantom types just fit this solution +more naturally.</p> +<h1 id="gadts">GADTs</h1> +<p>Some people have noted that we could achieve the same thing using <code>GADTs</code> +(Generalised Algebraic Data Types), which is an extension to the Haskell&rsquo;s type +system. I didn&rsquo;t want to dive into this at first, since GADTs are much harder +to understand for non-Haskell programmers, but let&rsquo;s show a simple +implementation of this example.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">Encrypted</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">PlainText</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">Message</span> a <span style="color:#81a1c1;font-weight:bold">where</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">EncryptedMessage</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">String</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">Encrypted</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">PlainTextMessage</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">String</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">PlainText</span> +</span></span></code></pre></div><p>The difference here is that we&rsquo;re basically creating typed value constructors +which automatically enforce the resulting type of the <code>Message</code>. For example if +we do <code>EncryptedMessage &quot;hello&quot;</code>, it will automatically have the type of +<code>Message Encrypted</code>. This might seem the same as the <code>newtype</code> solution +mentioned above, but by using <code>GADTs</code> we can still write a generic +<code>messageLength</code> function, exactly as we did previously.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">messageLength</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Message</span> a <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Int</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">messageLength</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">EncryptedMessage</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> length m +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">messageLength</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">PlainTextMessage</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> length m +</span></span></code></pre></div><p>The difference here is, that we need to pattern match on both of the +constructors. An implementation fo the <code>send</code> function might look something +like this.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">send</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">Encrypted</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">send</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">EncryptedMessage</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#616e87;font-style:italic">-- some magic</span> +</span></span></code></pre></div><p>If you&rsquo;re familiar a bit with Haskell, you might be thinking that this function +is not total and could produce a non-exhaustive pattern match error. But in +fact it can&rsquo;t, because it expects it&rsquo;s argument of the type <code>Message Encrypted</code>. If you try to call it with a <code>PlainText</code> message it would be a type +error.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">send</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">PlainTextMessage</span> <span style="color:#a3be8c">&#34;hello&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">-- type error</span> +</span></span></code></pre></div><p>This is one of the beauties of <code>GADTs</code>. If you&rsquo;re interested in learning more +about them, I recommend reading <a href="http://www.haskell.org/haskellwiki/Generalised_algebraic_datatype">the Haskell Wiki +page</a> as +well as <a href="http://www.haskell.org/haskellwiki/GADTs_for_dummies">many</a> +<a href="http://en.wikibooks.org/wiki/Haskell/GADT">others</a>. I&rsquo;ll probably write +another followup article that explains just <code>GADTs</code>, just because they&rsquo;re such +a rich feature.</p> +<h1 id="tell-dont-ask">Tell don&rsquo;t ask™</h1> +<p><a href="http://patrickdlogan.blogspot.cz/2014/07/being-safer-in-dynamic-languages.html">Patrick Dlogan actually took the time to write an article as a reaction to +mine</a>, +where he shows a solution in which messages know how to encrypt themselves, +which allows you to get rid of the <code>if</code> check in a dynamic language. Here&rsquo;s +also a similar response from <a href="https://lobste.rs/s/5ekbap/using_phantom_types_in_haskell_for_extra_safety">comments on +Lobste.rs</a>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#8fbcbb">Message</span> <span style="color:#81a1c1">=</span> <span style="color:#8fbcbb">Struct</span><span style="color:#81a1c1">.</span>new<span style="color:#eceff4">(</span><span style="color:#a3be8c">:text</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">def</span> <span style="color:#88c0d0">ciphertext</span> +</span></span><span style="display:flex;"><span> @ciphertext <span style="color:#81a1c1">||=</span> <span style="color:#616e87;font-style:italic"># encrypt plain text logic</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">end</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">end</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">def</span> <span style="color:#88c0d0">send_message</span><span style="color:#eceff4">(</span>message<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic"># send using message.ciphertext</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">end</span> +</span></span></code></pre></div><p>We could label both of these solutions as a kind of <em>tell don&rsquo;t ask™</em> +principle. Basically what it means is that instead of performing the encryption +first, and then sending the message out, the encryption step is being run +directly when sending the message.</p> +<p>Here&rsquo;s how something similar might look in Haskell. We&rsquo;re simply doing the +encryption when sending the message.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">send</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">send</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Message</span> m<span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">=</span> someMagic <span style="color:#eceff4">(</span>encrypt m<span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>Now this might make sense in some cases, but what if there is more than one +place where a message can get encrypted? We could solve that by making +<code>encrypt</code> do nothing for already encrypted messages, but there are downsides to +doing that.</p> +<p>First of all it&rsquo;s important to realize that this is restructuring how the +program works. If <code>encrypt</code> is something that can fail we&rsquo;ve effectively moved +that failure to a different place. If <code>encrypt</code> was throwing an exception that +had to be handled, now that error handling needs to happen in the place of the +caller of <code>send</code> (assuming it&rsquo;s not something we can deal right in place.)</p> +<p>Another more important reason why this wouldn&rsquo;t always be possible is that the +code for constructing messages might be outside of our control. Say that all of +the logic is hidden in a library which you can&rsquo;t change for various reason, or +these are just some data types you&rsquo;re receiving from an API.</p> +<p>The library could still make use of Phantom Types to safely tag the values on +the type level, while you wouldn&rsquo;t be able to apply this <em>tell don&rsquo;t ask</em> +approach, since the <code>encrypt</code> logic is not in your control.</p> +<p>I guess the TL;DR here is that by using the type system in a smart way we can +add additional checks that are verified at compile time, that increase the +safety of our programs. It&rsquo;s not a technique for re-structuring or re-designing +a portion of the codebase.</p> + + + + + Using Phantom Types for Extra Safety + https://blog.jakuba.net/2014-07-08-using-phantom-types-for-extra-safety/ + Tue, 08 Jul 2014 00:00:00 +0000 + + https://blog.jakuba.net/2014-07-08-using-phantom-types-for-extra-safety/ + <p>If you’ve been programming in a dynamic language, you’ve probably heard that +type systems can catch more errors before your application even gets run. The +more powerful the type system is, the more you can express in it. And because +we’re talking about Haskell, we have a great number of tools at our disposal +when trying to express things in terms of the types.</p> +<p>Why is this important? Sometimes a function has an expectation about the value +that it’s receiving. In most imperative languages those expectations are +implicit and up to the programmer to hold, such as the following</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">def</span> <span style="color:#88c0d0">foo</span><span style="color:#eceff4">(</span>bar<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> bar<span style="color:#81a1c1">.</span>baz +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">end</span> +</span></span></code></pre></div><p>In this example the function <code>foo</code> implicitly expects an object which is not +<code>nil</code>. If you call <code>foo(nil)</code>, you’ll get an exception at runtime. To combat +this we usually write unit tests to verify that our system will never get into +such state that the function would get passed in a <code>nil</code>. Now this is a very +simple example, let’s take a look at a more complicated one.</p> +<p>Imagine you’re writing a service which receives messages from users, encrypts +them, and sends them on through an unsecured channel. The messages are both +being sent and received as base64 encoded strings, so you can’t easily tell if +a message has been encrypted by just inspecting it.</p> +<p>Here’s how we could represent the message in Haskell and in Ruby, just so that +we can compare the code.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">String</span> +</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">class</span> <span style="color:#8fbcbb">Message</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">attr_accessor</span> <span style="color:#a3be8c">:text</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">def</span> <span style="color:#88c0d0">initialize</span><span style="color:#eceff4">(</span>text<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> @text <span style="color:#81a1c1">=</span> text +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">end</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">end</span> +</span></span></code></pre></div><p>Now this is all well and good, but we also want to keep track if the message +has been encrypted or if it is still in plain text. To do this in Haskell we’ll +use a simple Algebraic Data Type, while in Ruby we’ll add an additional +attribute called <code>encrypted</code>, which will default to <code>false</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">PlainText</span> <span style="color:#81a1c1">String</span> <span style="color:#81a1c1">|</span> <span style="color:#81a1c1">Encrypted</span> <span style="color:#81a1c1">String</span> +</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">class</span> <span style="color:#8fbcbb">Message</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">attr_accessor</span> <span style="color:#a3be8c">:text</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">:encrypted</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">def</span> <span style="color:#88c0d0">initialize</span><span style="color:#eceff4">(</span>text<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> @text <span style="color:#81a1c1">=</span> text +</span></span><span style="display:flex;"><span> @encrypted <span style="color:#81a1c1">=</span> <span style="color:#81a1c1">false</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">end</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">end</span> +</span></span></code></pre></div><p>While the Haskell version is less verbose, it doesn’t give us much more safety +guarantees at this point. Let’s say we want to define a function which sends a +message. We want it only to accept a message that has been encrypted, since +sending a plain text message is unsafe and should not be allowed.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">def</span> <span style="color:#88c0d0">send_message</span><span style="color:#eceff4">(</span>message<span style="color:#eceff4">,</span> recipient<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">if</span> message<span style="color:#81a1c1">.</span>encrypted +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic"># send logic</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">else</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">raise</span> <span style="color:#8fbcbb">ArgumentError</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;Can’t send a plain text message&#34;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">end</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">end</span> +</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">send</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Recipient</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">send</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">Encrypted</span> m<span style="color:#eceff4">)</span> recipient <span style="color:#81a1c1;font-weight:bold">=</span> some magic with m +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">send</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">PlainText</span> <span style="color:#81a1c1;font-weight:bold">_</span><span style="color:#eceff4">)</span> <span style="color:#81a1c1;font-weight:bold">_</span> <span style="color:#81a1c1;font-weight:bold">=</span> undefined +</span></span></code></pre></div><p>It doesn’t really matter how we chose to represent this in Haskell. Even if we +used a <code>Maybe</code> or <code>Either</code> to handle the failure, we would still have to handle +this at runtime. Which means only one thing, this function needs to be for the +edge case that we pass in a message in an invalid state, and we would also need +to test the error handling. This is as far as we can go with Ruby, since +there’s no way to enforce more structure into the program.</p> +<p>But wouldn’t it be much nicer if a program that’s trying to call <code>send</code> with +<code>PlainText</code> message would get rejected by the type checker? Such program is not +valid in our business domain and it shouldn&rsquo;t compile. If we manage to do that, +we can save ourselves the error handling, and also writing tests for the error +handling.</p> +<p>To be able to do this we need to express the relationship between the +<code>Encrypted</code> message and the <code>send</code> function at the type level. The trick that +allows us to do this is called <code>Phantom Types</code>, but to understand those, first +let&rsquo;s take a look at simple parametric data types in Haskell. They are very +similar to templates or generics in C++/C#/Java and many other languages. +Here&rsquo;s a simple parametric type:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">Maybe</span> a <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Just</span> a <span style="color:#81a1c1">|</span> <span style="color:#81a1c1">Nothing</span> +</span></span></code></pre></div><p>The <code>a</code> on the left side is simply a <em>type parameter</em>. If we choose to create a +value such as <code>Just 3</code>, it would have the type of <code>Maybe Int</code>.</p> +<h2 id="phantom-types">Phantom Types</h2> +<p>A type is called a Phantom Type if it has a type parameter which only appears +on the left hand side, but is not used by any of the value constructors. Here&rsquo;s +how we could need to modify our <code>Message</code> type to make it into a Phantom Type.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">Message</span> a <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">String</span> +</span></span></code></pre></div><p>This allows us to have things like <code>Message Int</code>, <code>Message String</code>, <code>Message (Maybe Char)</code>, and so on. In itself it might not look appealing, since no +matter what type we use it will still have a single value constructor which +works with <code>String</code>s. But let&rsquo;s expand this further by adding two empty data +types, one for each type of the message.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">Encrypted</span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">data</span> <span style="color:#81a1c1">PlainText</span> +</span></span></code></pre></div><p>This gives us an option to create both <code>Message Encrypted</code> and <code>Message PlainText</code> types. Remember that even if we&rsquo;re not using the type parameter in +any of the constructors, it is still verified by the type system, which means +we can change our <code>send</code> function to have the following signature.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">send</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">Encrypted</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Recipient</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">IO</span> <span style="color:#81a1c1">()</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">encrypt</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">PlainText</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">Encrypted</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">decrypt</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">Encrypted</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">PlainText</span> +</span></span></code></pre></div><p>The last thing we would need to do to make this completely safe is to make the +constructor for <code>Message</code> private and only export a function for creating a new +instance of the type. This makes it impossible to change the <em>state</em> of the +<code>Message</code> type in any other way, but by using our <code>encrypt</code> and <code>decrypt</code> +functions, because you wouldn&rsquo;t be able to use pattern matching to extract the +inner value. The function for creating a new <code>Message</code> could look something +like this</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">newMessage</span> <span style="color:#81a1c1;font-weight:bold">::</span> <span style="color:#81a1c1">String</span> <span style="color:#81a1c1;font-weight:bold">-&gt;</span> <span style="color:#81a1c1">Message</span> <span style="color:#81a1c1">PlainText</span> +</span></span><span style="display:flex;"><span><span style="color:#88c0d0">newMessage</span> s <span style="color:#81a1c1;font-weight:bold">=</span> <span style="color:#81a1c1">Message</span> s +</span></span></code></pre></div><p>Now armed with the power of Phantom Types, the following would be rejected by +the type system, making it impossible to send plain-text messages.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-haskell" data-lang="haskell"><span style="display:flex;"><span><span style="color:#88c0d0">send</span> <span style="color:#eceff4">(</span>newMessage <span style="color:#a3be8c">&#34;hello!&#34;</span><span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#34;john@example.com&#34;</span> +</span></span></code></pre></div><p>A similar thing could also be implemented using <a href="http://www.haskell.org/haskellwiki/Generalised_algebraic_datatype">Generalised Algebraic Data +Types</a> +(GADTs), but that&rsquo;s in the scope of this article. If you&rsquo;re interested in +learning more, I recommend checking out the <a href="http://www.haskell.org/haskellwiki/Phantom_type">Haskell Wiki article about Phantom +Types</a>, which has some great +examples, or the <a href="http://en.wikibooks.org/wiki/Haskell/Phantom_types">WikiBooks +entry</a>.</p> +<p><strong>Update:</strong> As it was just pointed out in the <a href="https://lobste.rs/s/5ekbap/using_phantom_types_in_haskell_for_extra_safety">comments on +Lobste.rs</a>, +it&rsquo;s worth noting that all of this safety guarantee comes for free. The +types are stripped when the program type checks and compiles, so there +is no runtime overhead. This might be something not so obvious to people +used to programming in dynamic languages.</p> + + + + + Evil Mode: How I Switched From VIM to Emacs + https://blog.jakuba.net/2014-06-23-evil-mode-how-to-switch-from-vim-to-emacs/ + Mon, 23 Jun 2014 00:00:00 +0000 + + https://blog.jakuba.net/2014-06-23-evil-mode-how-to-switch-from-vim-to-emacs/ + <p>I&rsquo;ve been a long time VIM user. I use it every day for all +of my work and side projects, writing blog posts, writing other +content, sometimes even for writing emails if the text is long +enough. VIM is like my home and I&rsquo;m deeply in love with it.</p> +<p>The problem is that VIM is a horrible IDE. It&rsquo;s an amazing and super +productive editor, but it really sucks at doing IDE-like things. Now +you might be thinking I&rsquo;m a noob who needs to click on good looking +buttons in RubyMine to get things done. No, that&rsquo;s not what I mean by +IDE &hellip; let me explain.</p> +<p>Most of my work in the past years has been either Ruby or +JavaScript. Those are dynamic languages with close to none IDE +support. You don&rsquo;t usually run a REPL and eval your Rails app, but +instead write a test, write some code, hit a button to run the test, +and occasionally reload the browser.</p> +<p>Most of the work is heavy editing of large amounts of source code, +which is what VIM excels at. Running the tests is easy as well, since +you can just bind it to a key with a single line of vimscript</p> +<pre><code>nnoremap &lt;leader&gt;t :!rspec %&lt;cr&gt; +</code></pre> +<p>This is all nice, but what if you want to use a language which has a +REPL? What if you want to display errors inline every time you save a file?</p> +<p>I can actually answer both of these right now. There were numerous +attempts to bring something REPL-like to VIM, but usually the outcome +is unusable. Most people I know don&rsquo;t even bother with this and use +<code>tmux</code>. Which is fine if this is the only problem you&rsquo;re trying to +solve, but there&rsquo;s more. Let&rsquo;s go to problem #2.</p> +<p>If you&rsquo;ve been using VIM for a while, you probably immediately thought +<em>Doesn&rsquo;t syntastic already display errors inline?</em>. Yes it does, but +it&rsquo;s doing so in a synchronous way. Which means if you&rsquo;re using a +checker which is slower than half a second, you will have a bad +time. This is especially true for <code>ghc-mod</code>, which takes up to 5 +seconds on my machine. There are alternatives that make this faster, +but this is still talking about a fast dev machine. When I&rsquo;m working +on my tiny 11&quot; Lenovo, it&rsquo;s just impossible to have Syntastic turned +on.</p> +<h2 id="evil-mode">Evil Mode</h2> +<p>I&rsquo;ve been using Emacs on and off for about 2-3 years now. But there +was always the feeling of being slow compared to VIM. Especially once +you get really fast at navigating in VIM, it&rsquo;s hard to use anything +else.</p> +<p>Then one night I decided to give Evil Mode. Every other editor +supports some sort of VIM emulation, but every single one of them I +tried fell short. But not Emacs. I am completely blown away by the +level of integration Evil Mode has. There are even ports of the most +popular VIM plugins into Evil Mode, such as Tim Pope&rsquo;s vim-surround.</p> +<p>Almost everything works out of the box, and even more, it works really +well with the built-in Emacs key-bindings. You can search, record +macros, jump around like you would in VIM, but you get the full power +of Emacs at your hand as well. This means you can be in the middle of +typing something and immediately press <code>C-c C-l</code> while still in insert +mode to load your file into the REPL. (Yes you still have to save the +file, but that can be done while in insert mode as well.)</p> +<p>There are things that I love about Emacs that I was missing in VIM, +and there are things about VIM that I was missing in Emacs, but Evil +Mode does such a great job at bringing the two together. It&rsquo;s hard to +describe this feeling in words. I can only imagine that the developers +behind it are very skilled VIM users.</p> +<h2 id="disadvantages">Disadvantages</h2> +<p>While most things work really nice with the default Emacs keymap, +there is one VIM feature that I had to disable, and that is <code>q</code>. The +reason for this is that <code>q</code> is being used at many places in Emacs to +close things, and sometimes it so happens that Evil Mode is turned on +in that window at the same time, which results in recording a macro +instead of closing the window.</p> +<p>Here&rsquo;s my complete list of customizations.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-elisp" data-lang="elisp"><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#88c0d0">define-key</span> evil-normal-state-map <span style="color:#eceff4">(</span>kbd <span style="color:#a3be8c">&#34;,f&#34;</span><span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#39;projectile-find-file</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#88c0d0">define-key</span> evil-normal-state-map <span style="color:#eceff4">(</span>kbd <span style="color:#a3be8c">&#34;,,&#34;</span><span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#39;evil-buffer</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#88c0d0">define-key</span> evil-normal-state-map <span style="color:#eceff4">(</span>kbd <span style="color:#a3be8c">&#34;q&#34;</span><span style="color:#eceff4">)</span> <span style="color:#8fbcbb">nil</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#88c0d0">define-key</span> evil-insert-state-map <span style="color:#eceff4">(</span>kbd <span style="color:#a3be8c">&#34;C-e&#34;</span><span style="color:#eceff4">)</span> <span style="color:#8fbcbb">nil</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#88c0d0">define-key</span> evil-insert-state-map <span style="color:#eceff4">(</span>kbd <span style="color:#a3be8c">&#34;C-d&#34;</span><span style="color:#eceff4">)</span> <span style="color:#8fbcbb">nil</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#88c0d0">define-key</span> evil-insert-state-map <span style="color:#eceff4">(</span>kbd <span style="color:#a3be8c">&#34;C-k&#34;</span><span style="color:#eceff4">)</span> <span style="color:#8fbcbb">nil</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#88c0d0">define-key</span> evil-insert-state-map <span style="color:#eceff4">(</span>kbd <span style="color:#a3be8c">&#34;C-g&#34;</span><span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#39;evil-normal-state</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#88c0d0">define-key</span> evil-visual-state-map <span style="color:#eceff4">(</span>kbd <span style="color:#a3be8c">&#34;C-c&#34;</span><span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#39;evil-normal-state</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#88c0d0">define-key</span> evil-motion-state-map <span style="color:#eceff4">(</span>kbd <span style="color:#a3be8c">&#34;C-e&#34;</span><span style="color:#eceff4">)</span> <span style="color:#8fbcbb">nil</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#88c0d0">define-key</span> evil-visual-state-map <span style="color:#eceff4">(</span>kbd <span style="color:#a3be8c">&#34;C-c&#34;</span><span style="color:#eceff4">)</span> <span style="color:#a3be8c">&#39;evil-exit-visual-state</span><span style="color:#eceff4">)</span> +</span></span></code></pre></div><p>Most of these are just minor inconveniences, though I really do +appreciate the level of customization available in Evil Mode. If +anything misbehaves, it&rsquo;s easy to just <code>C-h k</code> and press the key, to +see which function gets invoked. After that it&rsquo;s just a matter of +looking at the source code, or simply overriding the key in the +specific mode.</p> +<p>Customizability (is that even a word?) is one of the reasons why I&rsquo;m +starting to like Emacs more and more. Even though I&rsquo;m not a big Lisp +fan, I still prefer it to vimscript any day of the week. Most of the +Elisp code out there is very readable and well commented, so it&rsquo;s not +that hard to dig into the source of the package you&rsquo;re using and try +to figure some things out. Having more customization options is also a +disadvantage to some extent, since Emacs packages are usually more +complex than the VIM counterparts and it takes more time to setup things.</p> +<p>I don&rsquo;t think I&rsquo;ll ever give up VIM entirely, mostly because I&rsquo;ve +invested many years into perfecting my Ruby workflow. That +being said, I don&rsquo;t mind switching to Emacs for other languages, where +the support is much better to begin with, and the price to pay in +terms of differences between evil mode and VIM is quite small. Maybe +one day I will be able to write Ruby in Emacs as well.</p> + + + + + Yesod is Fun + https://blog.jakuba.net/2014-05-15-yesod-is-fun/ + Thu, 15 May 2014 00:00:00 +0000 + + https://blog.jakuba.net/2014-05-15-yesod-is-fun/ + <p>I&rsquo;ve been trying many Haskell web frameworks over the past few weeks. I wrote +one small app with <a href="http://simple.cx">Simple</a>, almost wrote another one with +<a href="https://github.com/scotty-web/scotty">Scotty</a>. Then decided it&rsquo;s time to take a +look at the big guys, <a href="http://happstack.com/">Happstack</a>, +<a href="http://snapframework.com/">Snap</a> and <a href="http://yesodweb.com/">Yesod</a>.</p> +<p>First I tried Happstack, which felt kind of OK and very understandable, mostly +because it doesn&rsquo;t seem to be trying to do much magic. This is really great for +learning, but then I stumbled when I found that it&rsquo;s not actually being +developed on GitHub. I know this in itself isn&rsquo;t an argument against Happstack, +but given that it seems to be the least popular and least used out of the +three, it definitely doesn&rsquo;t help it get higher on my list.</p> +<p>Next goes Snap, which I have really mixed feelings about. At first Snap +feels very simple and well documented, and <a href="http://snapforbeginners.com/">even has a +book</a>, which I immediately bought. There +is even an IRC room with more than 20 people in it. I was so excited. +But then small things started to pile up and I became less and less +excited.</p> +<p>While the documentation seems to be sufficient, I couldn&rsquo;t really found +the answers to many of my questions, the IRC room while full of people +is very idle and the GitHub repo seems quite dead. I will definitely +give Snap another try in the next weeks.</p> +<p>And then came Yesod. I&rsquo;ve been avoiding Yesod for quite some time, +mostly because I assumed it&rsquo;s a big ball of magic, as Rails is, and I +wanted to avoid that in the beginning. I also tried it about a year ago +and failed, but this time I decided to really dig in and write something +in Yesod.</p> +<p>I haven&rsquo;t really made much progress yet, but there&rsquo;s an interesting +factor that was missing from the other frameworks (apart from Simple), +and that is fun. <strong>Yesod is fun.</strong></p> +<p>Everything worked out of the box and the way I expected. Even the +automatic migrations which I didn&rsquo;t like at first surprised me by doing +the right thing every time I used it. While there is a lot of Template +Haskell being used it actually does make a lot of sense after studying +it for a while. It might make some things a bit more obscure, but I find +it being used very reasonably and in ways which make sense to me.</p> +<p>Also every time I <a href="http://github.com/yesodweb">check out any of the repos for +Yesod</a> there has been a new commit, usually +a few hours ago. Comparing this to Snap which is <a href="https://github.com/snapframework/snap/graphs/commit-activity">fairly +inactive</a> +I would say and I have yet another bonus point for Yesod. The #yesod +channel on IRC is also really active, and the documentation is +outstanding. There&rsquo;s also FP Complete, which is another huge bonus point +for Yesod.</p> +<p>All of this put together and I have a clear winner, at least for now.</p> + + + + + Duplication in Tests Is Sometimes Good + https://blog.jakuba.net/2014-05-04-duplication-in-tests-is-sometimes-good/ + Sun, 04 May 2014 00:00:00 +0000 + + https://blog.jakuba.net/2014-05-04-duplication-in-tests-is-sometimes-good/ + <p>Having powerful tools like RSpec gives us so much power, that what was +once a nice suite of readable specs becomes a huge bunch of unreadable +mess, just because someone tried to DRY it up.</p> +<p>When writing your production code, there&rsquo;s a good reason to keep the +code DRY. Most of the times having duplication in your code can be a +smell. But just because something sometimes smells, it doesn&rsquo;t mean you +should try to fix it all the time. This becomes even more important when +writing tests.</p> +<p>Let&rsquo;s compare these two examples</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>specify <span style="color:#a3be8c">:draft?</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> build<span style="color:#eceff4">(</span><span style="color:#a3be8c">:post</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">status</span><span style="color:#eceff4">:</span> <span style="color:#8fbcbb">Post</span><span style="color:#81a1c1">::</span><span style="color:#8fbcbb">DRAFT</span><span style="color:#eceff4">)</span><span style="color:#81a1c1">.</span>should be_draft +</span></span><span style="display:flex;"><span> build<span style="color:#eceff4">(</span><span style="color:#a3be8c">:post</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">status</span><span style="color:#eceff4">:</span> <span style="color:#8fbcbb">Post</span><span style="color:#81a1c1">::</span><span style="color:#8fbcbb">PUBLISHED</span><span style="color:#eceff4">)</span><span style="color:#81a1c1">.</span>should_not be_draft +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">end</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>specify <span style="color:#a3be8c">:published?</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> build<span style="color:#eceff4">(</span><span style="color:#a3be8c">:post</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">status</span><span style="color:#eceff4">:</span> <span style="color:#8fbcbb">Post</span><span style="color:#81a1c1">::</span><span style="color:#8fbcbb">DRAFT</span><span style="color:#eceff4">)</span><span style="color:#81a1c1">.</span>should_not be_published +</span></span><span style="display:flex;"><span> build<span style="color:#eceff4">(</span><span style="color:#a3be8c">:post</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">status</span><span style="color:#eceff4">:</span> <span style="color:#8fbcbb">Post</span><span style="color:#81a1c1">::</span><span style="color:#8fbcbb">PUBLISHED</span><span style="color:#eceff4">)</span><span style="color:#81a1c1">.</span>should be_published +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">end</span> +</span></span></code></pre></div><p>This looks ok, but could we maybe refactor it a little bit to avoid the +duplication there?</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>let<span style="color:#eceff4">(</span><span style="color:#a3be8c">:draft_post</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> build<span style="color:#eceff4">(</span><span style="color:#a3be8c">:post</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">status</span><span style="color:#eceff4">:</span> <span style="color:#8fbcbb">Post</span><span style="color:#81a1c1">::</span><span style="color:#8fbcbb">DRAFT</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span>let<span style="color:#eceff4">(</span><span style="color:#a3be8c">:published_post</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> build<span style="color:#eceff4">(</span><span style="color:#a3be8c">:post</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">status</span><span style="color:#eceff4">:</span> <span style="color:#8fbcbb">Post</span><span style="color:#81a1c1">::</span><span style="color:#8fbcbb">PUBLISHED</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>specify <span style="color:#a3be8c">:draft?</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> draft_post<span style="color:#81a1c1">.</span>should be_draft +</span></span><span style="display:flex;"><span> published_post<span style="color:#81a1c1">.</span>should_not be_draft +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">end</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>specify <span style="color:#a3be8c">:published?</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> draft_post<span style="color:#81a1c1">.</span>should_not be_published +</span></span><span style="display:flex;"><span> published_post<span style="color:#81a1c1">.</span>should be_published +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">end</span> +</span></span></code></pre></div><p>Now that we don&rsquo;t have that ugly duplication anymore, let&rsquo;s ask +ourselves if the refactored test is really better? There is less +duplication, but we&rsquo;ve split each test in two parts. The problem comes +when one of these tests fails, and suddenly you need to look around in +the whole file to see where the setup is being performed.</p> +<p>This becomes even worse if you use more than one <code>let</code> to setup your +specs, such as</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>let<span style="color:#eceff4">(</span><span style="color:#a3be8c">:user1</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> create<span style="color:#eceff4">(</span><span style="color:#a3be8c">:user</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span>let<span style="color:#eceff4">(</span><span style="color:#a3be8c">:user2</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> create<span style="color:#eceff4">(</span><span style="color:#a3be8c">:user</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span>let<span style="color:#eceff4">(</span><span style="color:#a3be8c">:post</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> create<span style="color:#eceff4">(</span><span style="color:#a3be8c">:post</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">user</span><span style="color:#eceff4">:</span> user1<span style="color:#eceff4">)</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span>let<span style="color:#eceff4">(</span><span style="color:#a3be8c">:admin</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> create<span style="color:#eceff4">(</span><span style="color:#a3be8c">:user</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">:admin</span><span style="color:#eceff4">)</span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>it <span style="color:#a3be8c">&#34;doesn&#39;t allow any other user to delete a post&#34;</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> user2<span style="color:#81a1c1">.</span>can_delete?<span style="color:#eceff4">(</span>post<span style="color:#eceff4">)</span><span style="color:#81a1c1">.</span>should be_false +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">end</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>it <span style="color:#a3be8c">&#34;allows admins to delete any post&#34;</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> admin<span style="color:#81a1c1">.</span>can_delete?<span style="color:#eceff4">(</span>post<span style="color:#eceff4">)</span><span style="color:#81a1c1">.</span>should be_true +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">end</span> +</span></span></code></pre></div><p>Imagine you have 20 tests like this for each context, and then define +some other variables in the context above. A single failure will force +you to scroll up and down and look around in 500 lines of test code, +instead of just seeing everything in one place, such as.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>it <span style="color:#a3be8c">&#34;doesn&#39;t allow any other user to delete a post&#34;</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> user1 <span style="color:#81a1c1">=</span> create<span style="color:#eceff4">(</span><span style="color:#a3be8c">:user</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> user2 <span style="color:#81a1c1">=</span> create<span style="color:#eceff4">(</span><span style="color:#a3be8c">:user</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> post <span style="color:#81a1c1">=</span> create<span style="color:#eceff4">(</span><span style="color:#a3be8c">:post</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">user</span><span style="color:#eceff4">:</span> user1<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> user2<span style="color:#81a1c1">.</span>can_delete?<span style="color:#eceff4">(</span>post<span style="color:#eceff4">)</span><span style="color:#81a1c1">.</span>should be_false +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">end</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>it <span style="color:#a3be8c">&#34;allows admin to delete any post&#34;</span> <span style="color:#81a1c1;font-weight:bold">do</span> +</span></span><span style="display:flex;"><span> post <span style="color:#81a1c1">=</span> create<span style="color:#eceff4">(</span><span style="color:#a3be8c">:post</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> admin <span style="color:#81a1c1">=</span> create<span style="color:#eceff4">(</span><span style="color:#a3be8c">:admin</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> admin<span style="color:#81a1c1">.</span>can_delete?<span style="color:#eceff4">(</span>post<span style="color:#eceff4">)</span><span style="color:#81a1c1">.</span>should be_true +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">end</span> +</span></span></code></pre></div><p>Is there more duplication? Yes. But if test #2 fails tomorrow, you&rsquo;ll +see what exactly is being tested, instead of having to spend 5 minutes +goofing around in the spec file to see what is actually going on.</p> + + + + + Light Table Plugin Tutorial + https://blog.jakuba.net/2014-01-13-light-table-plugin-tutorial/ + Mon, 13 Jan 2014 00:00:00 +0000 + + https://blog.jakuba.net/2014-01-13-light-table-plugin-tutorial/ + <p>I&rsquo;ve been playing around with Light Table since the day its source code was released (<a href="https://github.com/darthdeus/LightTable-Ruby">even made a tiny Ruby plugin</a>).</p> +<p>First of all, Light Table is <a href="http://www.chris-granger.com/2013/01/24/the-ide-as-data/">based on the BOT architecture</a>. Which means there are three core concepts: behaviors, objects and tags. If you have any experience with Node.js or event driven programming, you&rsquo;ll have an easy time understanding the concepts.</p> +<p>Imagine you have a button which listens on a click event and displays a notice to the user when it&rsquo;s clicked</p> +<p>Using jQuery that could be as simple as the following</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span><span style="color:#eceff4">&lt;</span><span style="color:#81a1c1">input</span> <span style="color:#8fbcbb">class</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;my-button&#34;</span> <span style="color:#8fbcbb">type</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;submit&#34;</span> <span style="color:#8fbcbb">value</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;Do work&#34;</span><span style="color:#eceff4">/&gt;</span> +</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>$<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;.my-button&#34;</span><span style="color:#eceff4">).</span>click<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> showProgress<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;I&#39;m doing some heavy lifting&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><p>But there are problems with this approach, especially from the Light Table&rsquo;s point of view. First of all there&rsquo;s no way to see the callback after it&rsquo;s been attached to the element. Which means you also can&rsquo;t change it easily at runtime. BOT allows us to decouple the object (the button) from the actual behavior it triggers (click).</p> +<p>Here&rsquo;s an implementation in ClojureScript. If you want to follow along with the tutorial, create a new file, for example <code>/tmp/tutorial.cljs</code>, press Ctrl-Space, type <code>Add Connection</code> and select <code>Light Table UI</code>. This will allow you to evaluate the ClojureScript directly into the running Light Table instance. But before continuing, add the following requires at the top of your file.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-clojure" data-lang="clojure"><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">ns </span>lt.tutorial +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">(</span><span style="color:#a3be8c">:require</span> <span style="color:#eceff4">[</span>lt.object <span style="color:#a3be8c">:as</span> object<span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">[</span>lt.objs.tabs <span style="color:#a3be8c">:as</span> tabs<span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">[</span>lt.objs.statusbar <span style="color:#a3be8c">:as</span> statusbar<span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">[</span>lt.objs.notifos <span style="color:#a3be8c">:as</span> notifos<span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">[</span>lt.util.js <span style="color:#a3be8c">:as</span> util<span style="color:#eceff4">])</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">(</span><span style="color:#a3be8c">:require-macros</span> <span style="color:#eceff4">[</span>lt.macros <span style="color:#a3be8c">:refer</span> <span style="color:#eceff4">[</span>behavior defui<span style="color:#eceff4">]]))</span> +</span></span></code></pre></div><p>From now on you should just be able to evaluate the current form under the cursor with Cmd-Enter.</p> +<p>Next we need to define our button, using the <code>defui</code> macro</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-clojure" data-lang="clojure"><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#88c0d0">defui</span> work-button <span style="color:#eceff4">[</span>this<span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">[</span><span style="color:#a3be8c">:input</span> <span style="color:#eceff4">{</span><span style="color:#a3be8c">:type</span> <span style="color:#a3be8c">&#34;submit&#34;</span> <span style="color:#a3be8c">:value</span> <span style="color:#a3be8c">&#34;Do work&#34;</span><span style="color:#eceff4">}]</span> +</span></span><span style="display:flex;"><span> <span style="color:#a3be8c">:click</span> <span style="color:#81a1c1">#</span><span style="color:#eceff4">(</span><span style="color:#88c0d0">object/raise</span> this <span style="color:#a3be8c">:clicked</span> %<span style="color:#eceff4">))</span> +</span></span></code></pre></div><p>This bit of code is fairly obvious, it results in a <code>&lt;input type=&quot;submit&quot; value=&quot;Do work&quot;/&gt;</code> with a click handler bound to our callback. <code>#(object/raise this :click %)</code> is just a shorthand for <code>(fn [e] (object/raise this :click e))</code>, where <code>object/raise</code> raises an event on the target object, in this case a click event. It has nothing to do with exceptions, despite its name.</p> +<p>Next we need to define our worker object.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-clojure" data-lang="clojure"><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#88c0d0">object/object*</span> <span style="color:#a3be8c">::worker</span> +</span></span><span style="display:flex;"><span> <span style="color:#a3be8c">:name</span> <span style="color:#a3be8c">&#34;A hard worker&#34;</span> +</span></span><span style="display:flex;"><span> <span style="color:#a3be8c">:behaviors</span> <span style="color:#eceff4">[</span><span style="color:#a3be8c">::work-on-click</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span> <span style="color:#a3be8c">:init</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">fn </span><span style="color:#eceff4">[</span>this<span style="color:#eceff4">]</span> <span style="color:#eceff4">(</span><span style="color:#88c0d0">work-button</span> this<span style="color:#eceff4">)))</span> +</span></span></code></pre></div><p>It&rsquo;s a hard worker who works when you click on it. Also note that the value returned from the <code>:init</code> function is used when the object is placed inside a tab, in this case it returns our button, bound to this object.</p> +<p>The behavior we&rsquo;re after will use the beautiful <code>notifos</code> library from Light Table, which displays these wonderful moving-squares-in-a-circle progress indicators.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-clojure" data-lang="clojure"><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#88c0d0">behavior</span> <span style="color:#a3be8c">::work-on-click</span> +</span></span><span style="display:flex;"><span> <span style="color:#a3be8c">:triggers</span> <span style="color:#81a1c1">#</span><span style="color:#eceff4">{</span><span style="color:#a3be8c">:clicked</span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#a3be8c">:reaction</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">fn </span><span style="color:#eceff4">[</span>this<span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">(</span><span style="color:#88c0d0">notifos/working</span> <span style="color:#a3be8c">&#34;Doing some heavy lifting!&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">(</span><span style="color:#88c0d0">util/wait</span> <span style="color:#b48ead">10000</span> <span style="color:#81a1c1">#</span><span style="color:#eceff4">(</span><span style="color:#88c0d0">statusbar/loader-set</span> <span style="color:#b48ead">0</span><span style="color:#eceff4">))))</span> +</span></span></code></pre></div><p>The behavior name has to be the same as in the object&rsquo;s <code>:behaviors</code> list. It has a set of <code>triggers</code> which trigger the <code>:reaction</code> function with the object passed in as an argument. In our case we&rsquo;ll just display a working indicator and then hide it after 10 seconds.</p> +<p>Now we&rsquo;re ready to create the object and add it as a tab.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-clojure" data-lang="clojure"><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">let </span><span style="color:#eceff4">[</span>worker <span style="color:#eceff4">(</span><span style="color:#88c0d0">object/create</span> <span style="color:#a3be8c">::worker</span><span style="color:#eceff4">)]</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">(</span><span style="color:#88c0d0">tabs/add!</span> worker<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">(</span><span style="color:#88c0d0">tabs/active!</span> worker<span style="color:#eceff4">))</span> +</span></span></code></pre></div><p>A new tab should appear with a button filling its content. When you click the button you should see a small progress bar at the bottom of the page, which will automatically disappear after 10 seconds.</p> +<p>Now you might&rsquo;ve noticed that the tab can&rsquo;t be closed. This is because there is no default behavior for closing a tab, since some tabs might want to prompt the user to save a file, others might have a completely different implementation. The good thing is that we can add this easily without having to restart Light Table.</p> +<p>We&rsquo;ll add another behavior which responds to the <code>:close</code> event (<a href="https://github.com/LightTable/LightTable/blob/master/src/lt/objs/docs.cljs#L23-L29">taken from docs.cljs</a>)</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-clojure" data-lang="clojure"><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#88c0d0">behavior</span> <span style="color:#a3be8c">::on-close-destroy</span> +</span></span><span style="display:flex;"><span> <span style="color:#a3be8c">:triggers</span> <span style="color:#81a1c1">#</span><span style="color:#eceff4">{</span><span style="color:#a3be8c">:close</span><span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#a3be8c">:reaction</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">fn </span><span style="color:#eceff4">[</span>this<span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">when-let </span><span style="color:#eceff4">[</span>ts <span style="color:#eceff4">(</span><span style="color:#a3be8c">:lt.objs.tabs/tabset</span> <span style="color:#81a1c1">@</span>this<span style="color:#eceff4">)]</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">(</span><span style="color:#81a1c1">when </span><span style="color:#eceff4">(</span><span style="color:#81a1c1">= </span><span style="color:#eceff4">(</span><span style="color:#81a1c1">count </span><span style="color:#eceff4">(</span><span style="color:#a3be8c">:objs</span> <span style="color:#81a1c1">@</span>ts<span style="color:#eceff4">))</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">(</span><span style="color:#88c0d0">tabs/rem-tabset</span> ts<span style="color:#eceff4">)))</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">(</span><span style="color:#88c0d0">object/raise</span> this <span style="color:#a3be8c">:destroy</span><span style="color:#eceff4">)))</span> +</span></span></code></pre></div><p>Next we need to tell our object to use this behavior by simply adding it to the behaviors list.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-clojure" data-lang="clojure"><span style="display:flex;"><span><span style="color:#eceff4">(</span><span style="color:#88c0d0">object/object*</span> <span style="color:#a3be8c">::worker</span> +</span></span><span style="display:flex;"><span> <span style="color:#a3be8c">:name</span> <span style="color:#a3be8c">&#34;A hard worker&#34;</span> +</span></span><span style="display:flex;"><span> <span style="color:#a3be8c">:behaviors</span> <span style="color:#eceff4">[</span><span style="color:#a3be8c">::work-on-click</span> <span style="color:#a3be8c">::on-close-destroy</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span> <span style="color:#a3be8c">:init</span> <span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">fn </span><span style="color:#eceff4">[</span>this<span style="color:#eceff4">]</span> <span style="color:#eceff4">(</span><span style="color:#88c0d0">work-button</span> this<span style="color:#eceff4">)))</span> +</span></span></code></pre></div><p>You don&rsquo;t need to restart anything, just eval the behavior and the object definiton and you should be able to close the tab :) That&rsquo;s how dynamic Light Table is.</p> +<p>For those who want to see the entire result, <a href="https://gist.github.com/darthdeus/8411616">here&rsquo;s a link to a gist</a> and also a gif screencast of the whole process :)</p> +<p><img src="https://i.imgur.com/PBsHkD7.gif" alt="screencast"></p> +<p>This tutorial is really just a small introduction to what Light Table can do, but it should give you a little bit of insight into how dynamic the whole system actually is.</p> +<hr> +<p><a href="https://news.ycombinator.com/item?id=7054884">Discuss this post on Hacker News</a> and <a href="http://www.reddit.com/r/programming/comments/1v5n82/light_table_plugin_tutorial_part_1/">Reddit</a></p> + + + + + PostgreSQL Basics by Example + https://blog.jakuba.net/2013-08-19-postgresql-basics-by-example/ + Mon, 19 Aug 2013 01:19:00 +0000 + + https://blog.jakuba.net/2013-08-19-postgresql-basics-by-example/ + <p>Connecting to a database</p> +<pre tabindex="0"><code>$ psql postgres # the default database +$ psql database_name +</code></pre><p>Connecting as a specific user</p> +<pre tabindex="0"><code>$ psql postgres john +$ psql -U john postgres +</code></pre><!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<p>Connecting to a host/port (by default <code>psql</code> uses a unix socket)</p> +<pre tabindex="0"><code>$ psql -h localhost -p 5432 postgres +</code></pre><p>You can also explicitly specify if you want to enter a password <code>-W</code> or not <code>-w</code></p> +<pre tabindex="0"><code>$ psql -w postgres +$ psql -W postgres +Password: +</code></pre><p>Once you&rsquo;re inside <code>psql</code> you can control the database. Here&rsquo;s a couple of handy commands</p> +<pre tabindex="0"><code>postgres=# \h # help on SQL commands +postgres=# \? # help on psql commands, such as \? and \h +postgres=# \l # list databases +postgres=# \c database_name # connect to a database +postgres=# \d # list of tables +postgres=# \d table_name # schema of a given table +postgres=# \du # list roles +postgres=# \e # edit in $EDITOR +</code></pre><p>At this point you can just type SQL statements and they&rsquo;ll be executed on the database you&rsquo;re currently +connected to.</p> +<h2 id="user-management">User Management</h2> +<p>Once your application goes into production, or basically anywhere outside of your dev machine, +you&rsquo;re going to want to create some users and restrict access.</p> +<p>We have two options for creating users, either from the shell via <code>createuser</code> or via SQL <code>CREATE ROLE</code></p> +<pre tabindex="0"><code>$ createuser john +postgres=# CREATE ROLE john; +</code></pre><p>One thing to note here is that by default users created with <code>CREATE ROLE</code> can&rsquo;t log in. To allow login you need to provide +the <code>LOGIN</code> attribute</p> +<pre tabindex="0"><code>postgres=# CREATE ROLE john LOGIN; +postgres=# CREATE ROLE john WITH LOGIN; # the same as above +postgres=# CREATE USER john; # alternative to CREATE ROLE which adds the LOGIN attribute +</code></pre><p>You can also add the <code>LOGIN</code> attribute with <code>ALTER ROLE</code></p> +<pre tabindex="0"><code>postgres=# ALTER ROLE john LOGIN; +postgres=# ALTER ROLE john NOLOGIN; # remove login +</code></pre><p>You can also specify multiple attributes when using <code>CREATE ROLE</code> or <code>ALTER ROLE</code>, but bare in mind that <code>ALTER ROLE</code> doesn&rsquo;t change the permissions the role already has which you don&rsquo;t specify.</p> +<pre tabindex="0"><code>postgres=# CREATE ROLE deploy SUPERUSER LOGIN; +CREATE ROLE +postgres=# ALTER ROLE deploy NOSUPERUSER CREATEDB; # the LOGIN privilege is not touched here +ALTER ROLE +postgres=# \du deploy + List of roles + Role name | Attributes | Member of +-----------+------------+----------- + deploy | Create DB | {} +</code></pre><p>There&rsquo;s an alternative to <code>CREATE ROLE john WITH LOGIN</code>, and that&rsquo;s <code>CREATE USER</code> which automatically creates the <code>LOGIN</code> permission. It is important to understand that users and roles are the same thing. In fact there&rsquo;s no such thing as a user in PostgreSQL, only a role with LOGIN permission</p> +<pre tabindex="0"><code>postgres=# CREATE USER john; +CREATE ROLE +postgres=# CREATE ROLE kate; +CREATE ROLE +postgres=# \du + List of roles + Role name | Attributes | Member of +-----------+------------------------------------------------+----------- + darth | Superuser, Create role, Create DB, Replication | {} + john | | {} + kate | Cannot login | {} +</code></pre><p>You can also create groups via <code>CREATE GROUP</code> (which is now aliased to <code>CREATE ROLE</code>), and then grant or revoke +access to other roles.</p> +<pre tabindex="0"><code>postgres=# CREATE GROUP admin LOGIN; +CREATE ROLE +postgres=# GRANT admin TO john; +GRANT ROLE +postgres=# \du + List of roles + Role name | Attributes | Member of +-----------+------------------------------------------------+----------- + admin | | {} + darth | Superuser, Create role, Create DB, Replication | {} + john | | {admin} + kate | Cannot login | {} +postgres=# REVOKE admin FROM john; +REVOKE ROLE +postgres=# \du + List of roles + Role name | Attributes | Member of +-----------+------------------------------------------------+----------- + admin | | {} + darth | Superuser, Create role, Create DB, Replication | {} + john | | {} + kate | Cannot login | {} +</code></pre> + + + + Ember.js: Testing Ember.js - part 1 + https://blog.jakuba.net/2013-02-19-testing-ember-dot-js-part-1/ + Tue, 19 Feb 2013 19:05:00 +0000 + + https://blog.jakuba.net/2013-02-19-testing-ember-dot-js-part-1/ + <p>Ever since I saw the <em>testing</em> slides from EmberCamp I was thinking +about testing. Up until now I&rsquo;ve been using Capybara which is really +really really slow.</p> +<p>But @joliss mentioned this thing called <code>Ember.testing</code> which should +automagically fix all of the async problems which make tests ugly, such +as waiting for the application to initialize and finish routing.</p> +<p>In its essence <code>Ember.testing = true</code> disables the automatic runloop, +which gives you the control to manually schedule asynchronous operations +to happen in a one-off runloop via <code>Ember.run</code>.</p> +<p><code>Ember.run</code> will run the given function inside a runloop and flush all +of the bindings before it finishes, which means you can render a view +inside <code>Ember.run</code> and check the DOM right after that. Here&rsquo;s an example +from the <code>Ember.View</code> tests</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>view <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>ContainerView<span style="color:#eceff4">.</span>create<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> childViews<span style="color:#81a1c1">:</span> <span style="color:#eceff4">[</span><span style="color:#a3be8c">&#34;child&#34;</span><span style="color:#eceff4">],</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> child<span style="color:#81a1c1">:</span> Ember<span style="color:#eceff4">.</span>View<span style="color:#eceff4">.</span>create<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> tagName<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#39;aside&#39;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">})</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>Ember<span style="color:#eceff4">.</span>run<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">(){</span> +</span></span><span style="display:flex;"><span> view<span style="color:#eceff4">.</span>createElement<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>equal<span style="color:#eceff4">(</span>view<span style="color:#eceff4">.</span>$<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#39;aside&#39;</span><span style="color:#eceff4">).</span>length<span style="color:#eceff4">,</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">);</span> +</span></span></code></pre></div><p>As you can see the <code>view.createElement()</code> happens inside the runloop +scheduled by <code>Ember.run</code> which will return only after the view was +completely rendered and all bindings flushed.</p> +<p>Let&rsquo;s take a look at a <a href="http://jsbin.com/ixupad/59/edit">complete example</a> +and take it apart step by step</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// Testing mode disables automatic runloop +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>Ember<span style="color:#eceff4">.</span>testing <span style="color:#81a1c1">=</span> <span style="color:#81a1c1;font-weight:bold">true</span><span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// Creating an application normally happens async, +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// which is why we have to wrap it in Ember.run +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>Ember<span style="color:#eceff4">.</span>run<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> App <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>Application<span style="color:#eceff4">.</span>create<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>Router<span style="color:#eceff4">.</span>map<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>route<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;home&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> path<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;/&#34;</span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>Store <span style="color:#81a1c1">=</span> DS<span style="color:#eceff4">.</span>Store<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> revision<span style="color:#81a1c1">:</span> <span style="color:#b48ead">11</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> adapter<span style="color:#81a1c1">:</span> DS<span style="color:#eceff4">.</span>FixtureAdapter<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// This will make the FixtureAdapter do everything synchronously +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// instead of using setTimeout, which is vital because setTimeout +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// happens outside of the runloop. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> simulateRemoteResponse<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">false</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">})</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>User <span style="color:#81a1c1">=</span> DS<span style="color:#eceff4">.</span>Model<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> name<span style="color:#81a1c1">:</span> DS<span style="color:#eceff4">.</span>attr<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;string&#34;</span><span style="color:#eceff4">)});</span> +</span></span><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">.</span>FIXTURES <span style="color:#81a1c1">=</span> <span style="color:#eceff4">[</span> <span style="color:#eceff4">{</span> id<span style="color:#81a1c1">:</span> <span style="color:#b48ead">1</span><span style="color:#eceff4">,</span> name<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;brohuda&#34;</span> <span style="color:#eceff4">}];</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>HomeRoute <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>Route<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> model<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">.</span>find<span style="color:#eceff4">(</span><span style="color:#b48ead">1</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// Enabling Ember.testing will also disable automatic initialization, +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// which forces us to initialize manually +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>Ember<span style="color:#eceff4">.</span>run<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> App<span style="color:#eceff4">.</span>initialize<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// In real life this would be an assertion, +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// here we&#39;ll just check if everything is rendered at this point in time. +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>$<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;p strong&#34;</span><span style="color:#eceff4">).</span>append<span style="color:#eceff4">(</span>$<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;h2&#34;</span><span style="color:#eceff4">).</span>text<span style="color:#eceff4">());</span> +</span></span></code></pre></div><p>Take the example apart, play with it and try to figure out what works +and what doesn&rsquo;t :)</p> +<p>If you see</p> +<pre tabindex="0"><code>assertion failed: You have turned on testing mode, which disabled the run-loop&#39;s autorun. +You will need to wrap any code with asynchronous side-effects in an Ember.run +</code></pre><p>it means that you forgot to wrap something in <code>Ember.run</code>. I hope this +is a good enough introduction. In one of the upcoming articles we&rsquo;ll +take a look at simple Ember application and try testing it with a +full featured testing framework.</p> + + + + + Ember.js: render, control, partial, view, template + https://blog.jakuba.net/2013-02-10-render-control-partial-view/ + Sun, 10 Feb 2013 21:29:00 +0000 + + https://blog.jakuba.net/2013-02-10-render-control-partial-view/ + <p>There are many ways one can DRY up templates when using Ember.js, it all +depends on what you&rsquo;re trying to achieve.</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<h2 id="partial--template">partial &amp;&amp; template</h2> +<p><code>{% raw %}{{partial &quot;foo&quot;}}{% endraw %}</code> will take a template +<code>foo.handlebars</code> and insert it without changing anything, which is +exactly the same as in Rails. There are no views created, no scope +changes, it just inserts the template right there.</p> +<p><code>{% raw %}{{template}}{% endraw %}</code> isn&rsquo;t really meant to be used anymore, so use +<code>{% raw %}{{partial}}{% endraw %}</code> instead.</p> +<h2 id="view">view</h2> +<p><code>{% raw %}{{view App.FooView}}{% endraw %}</code> will create an instance of +<code>App.FooView</code> (with <code>foo.handlebars</code> template unless you override the +name) and insert it in place. You can bind on properties of the view, +such as <code>{% raw %}{{view App.FooView contentBinding=&quot;foobar&quot;}}{% endraw %}</code>, +or just specify a property directly <code>{% raw %}{{view App.FooView class=&quot;foobar&quot;}}{% endraw %}</code>.</p> +<p>This is a low level thing and is mostly used to instantiate simple +views, such as <code>{% raw %}{{view Ember.TextField valueBinding=&quot;name&quot; class=&quot;username&quot;}}{% endraw %}</code></p> +<h2 id="render--control">render &amp;&amp; control</h2> +<p>Most of the time you&rsquo;re looking to use <code>{% raw %}{{render}}{% endraw %}</code> instead of +<code>{% raw %}{{view}}{% endraw %}</code> as it offers better means of +abstraction. <code>{% raw %}{{render &quot;foo&quot; bar}}{% endraw %}</code> will create a +<code>App.FooController</code> and bind it&rsquo;s content to <code>bar</code>. It also creates a +<code>App.FooView</code> and renders a <code>foo</code> template.</p> +<p>One drawback is that <code>{% raw %}{{render}}{% endraw %}</code> <strong>can not be called multiple times on +a single route</strong>. If you need a self sustainable widget which can be +created any number of times you want, you&rsquo;re looking for <code>{% raw %}{{control}}{% endraw %}</code> +which has exactly the same effect as <code>{% raw %}{{render}}{% endraw %}</code>, but it will have a new +controller instance every time you call it, while <code>{% raw %}{{render}w{% endraw %}</code> uses a +singleton controller.</p> +<p>Please keep in mind that <code>{% raw %}{{control}}{% endraw %}</code> is currently under heavy +development and will probably change soon, because of the high number of +issues there are with it.</p> + + + + + Ember.js: Router Request Lifecycle + https://blog.jakuba.net/2013-02-08-router-request-lifecycle/ + Fri, 08 Feb 2013 16:59:00 +0000 + + https://blog.jakuba.net/2013-02-08-router-request-lifecycle/ + <p>Router is the core part of Ember. Every time we go to a new URL it means +the route object is called with our params and stuff. These are the +hooks sorted in order in which they are called</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<ul> +<li>enter (private)</li> +<li>activate - executed when entering the route</li> +<li>deserialize (private)</li> +<li>model (formely deserialize) - takes the params and returns a model +which is set to the route&rsquo;s <code>currentModel</code></li> +<li>serialize - used to generate dynamic segments in the URL from a model</li> +<li>setupController - takes <code>currentModel</code> and sets it to the controller&rsquo;s +<code>content</code> by default</li> +<li>renderTemplate - takes current controller and what <code>model</code> returns and +renders the template with an appropriate name</li> +<li>deactivate - executed when exiting the route (called by exit +internally)</li> +<li>exit (private, requires call to <code>this._super</code>)</li> +</ul> +<p>Now let&rsquo;s take a look at them in more detail</p> +<h2 id="activatedeactivate"><code>activate</code>/<code>deactivate</code></h2> +<p>These were formely known as <code>enter</code>/<code>exit</code>, which are now marked as +private. <code>activate</code> will be executed when user enters a route, be it +from a transition or from a URL directly, and <code>deactivate</code> is executed +when user transitions away from the route.</p> +<p>One of the most common use cases for me is doing a transaction rollback +in <code>deactivate</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>PostsNewRoute <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>Route<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> deactivate<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>modelFor<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;postsNew&#34;</span><span style="color:#eceff4">).</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;transaction&#34;</span><span style="color:#eceff4">).</span>rollback<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><p>I find this mostly useful when having a <em>new record form</em> (or even when +editing a record), where you basically want to rollback any changes +which happened when the user exits the route. It doesn&rsquo;t matter if the +user submits the form first, because then the transaction will be +comitted and there will be nothing to rollback.</p> +<h2 id="modelserialize"><code>model</code>/<code>serialize</code></h2> +<p>To allow Ember to work with dynamic segments in the URLs we need to +teach it how to serialize and deserialize our models. When we enter a +URL directly (or reload the page) <code>model</code> will be called with params +from the dynamic segments. Let&rsquo;s take a look at an example</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>Router<span style="color:#eceff4">.</span>map<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>resource<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;post&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> path<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;/:post_id&#34;</span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>PostRoute <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>Route<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> model<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">(</span>params<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> App<span style="color:#eceff4">.</span>Post<span style="color:#eceff4">.</span>find<span style="color:#eceff4">(</span>params<span style="color:#eceff4">.</span>post_id<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><p>This is exactly what Ember will auto generate for us, along with a +serialize hook</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>PostRoute <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>Route<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> model<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">(</span>params<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> App<span style="color:#eceff4">.</span>Post<span style="color:#eceff4">.</span>find<span style="color:#eceff4">(</span>params<span style="color:#eceff4">.</span>post_id<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">},</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> serialize<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">(</span>model<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> <span style="color:#eceff4">{</span> post_id<span style="color:#81a1c1">:</span> model<span style="color:#eceff4">.</span>id <span style="color:#eceff4">};</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><p>it is important to note here that if we&rsquo;re transitioning from a +different route our <code>model</code> hook <em>will not be called</em>.</p> +<h2 id="setupcontroller"><code>setupController</code></h2> +<p>One step further after <code>model</code> comes <code>setupController</code>, which is meant +to set additional properties on the controller, or override it&rsquo;s +<code>content</code>.</p> +<p>But beware, there is no autogenerated <code>setupController</code> hook which sets to <code>content</code>, +this is done even before <code>setupController</code> is called <a href="https://github.com/emberjs/ember.js/blob/master/packages/ember-routing/lib/system/route.js#L79-82">in the <code>setup</code> hook</a> of the route. This is basically simulates the following:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>setupController<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">(</span>controller<span style="color:#eceff4">,</span> model<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> controller<span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;content&#34;</span><span style="color:#eceff4">,</span> model<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>But it also means we can set additional properties on the controller +without needing to explicitly set the content</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>setupController<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">(</span>controller<span style="color:#eceff4">,</span> model<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> controller<span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;foo&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;bar&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><h2 id="rendertemplate"><code>renderTemplate</code></h2> +<p>The last one of the hooks is <code>renderTemplate</code> where you tell which +template you want to render in which outlet.</p> +<p>By default <code>renderTemplate</code> will call <code>this.render</code> as follows</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>PostRoute <span style="color:#81a1c1">=</span> App<span style="color:#eceff4">.</span>Route<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> renderTemplate<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>render<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;post&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> into<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;application&#34;</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> outlet<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;main&#34;</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> controller<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;post&#34;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><p>In this case <code>render</code> will render the <code>post</code> template into the +<code>application</code> template&rsquo;s <code>main</code> outlet with the <code>PostController</code>.</p> +<p>This is the place where you can chose to render into other outlets. For +example let&rsquo;s say that your <code>application</code> template has a sidebar outlet +<code>{{outlet sidebar}}</code>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>PostRoute <span style="color:#81a1c1">=</span> App<span style="color:#eceff4">.</span>Route<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> renderTemplate<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// render with the defaults +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>render<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// and once more for the sidebar outlet +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>render<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;similarPosts&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> into<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;application&#34;</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> outlet<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;sidebar&#34;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><h2 id="important-notes-about-controllerfor-and-modelfor">Important notes about <code>controllerFor</code> and <code>modelFor</code></h2> +<p>While calling <code>controllerFor(&quot;posts&quot;)</code> returns an instance of +<code>PostsController</code>, calling <code>modelFor(&quot;posts&quot;)</code> <strong>doesn&rsquo;t return +<code>content</code> +of the <code>PostController</code></strong>. Instead it looks up the <code>PostsRoute</code> and +returns it&rsquo;s <code>currentModel</code> which is set when we return a value from the +<code>model</code> hook.</p> +<p>Let&rsquo;s see an example</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>PostsRoute <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>Route<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> setupController<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">(</span>controller<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> controller<span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;content&#34;</span><span style="color:#eceff4">,</span> App<span style="color:#eceff4">.</span>Post<span style="color:#eceff4">.</span>find<span style="color:#eceff4">());</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><p>This will cause issues if we decide to use <code>modelFor</code> later on. +<code>PostsRoute</code> will not have anything in <code>currentModel</code> and <code>modelFor</code> +will return undefined, which might look weird as the controller has a +content properly set.</p> + + + + + Ember.js: Using Transactions in Ember Data - part 1 + https://blog.jakuba.net/2013-02-02-using-transactions-in-ember-data/ + Sat, 02 Feb 2013 14:15:00 +0000 + + https://blog.jakuba.net/2013-02-02-using-transactions-in-ember-data/ + <p>We talked about transactions in <a href="http://darthdeus.github.com/blog/2013/01/27/ember-data-in-depth/">one of the previous articles</a> +(read it if you haven&rsquo;t already), but we didn&rsquo;t really touch on when to +use them in real world. One of the most common use cases for me is when +I just want to manage a single record while there are many changes +happening on the page.</p> +<p>Adding a record to a transaction is simple</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// say that we are in a controller +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>store <span style="color:#81a1c1">=</span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;store&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// this ALWAYS returns a new transaction +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>transaction <span style="color:#81a1c1">=</span> store<span style="color:#eceff4">.</span>transaction<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>user <span style="color:#81a1c1">=</span> App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">.</span>find<span style="color:#eceff4">(</span><span style="color:#b48ead">1</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>transaction<span style="color:#eceff4">.</span>add<span style="color:#eceff4">(</span>user<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>transaction<span style="color:#eceff4">.</span>toString<span style="color:#eceff4">();</span> <span style="color:#616e87;font-style:italic">// =&gt; &#34;&lt;DS.Transaction:ember955&gt;&#34; +</span></span></span></code></pre></div><p>Now this is obvious, but what if we need to commit the transaction in a +completely different action? Do we need to store the instance somewhere +to use it later?</p> +<p>The answer is NO, we can always return the transaction in which the +record is by calling <code>.get(&quot;transaction&quot;)</code>. We can even do it if we +decide to fetch the user again in a completely different part of the +application.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>user <span style="color:#81a1c1">=</span> App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">.</span>find<span style="color:#eceff4">(</span><span style="color:#b48ead">1</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;transaction&#34;</span><span style="color:#eceff4">).</span>toString<span style="color:#eceff4">();</span> <span style="color:#616e87;font-style:italic">// =&gt; &#34;&lt;DS.Transaction:ember955&gt;&#34; +</span></span></span></code></pre></div><p>It doesn&rsquo;t matter in which part of the application you add the record to +a transaction because you can always retrieve the correct instance +later.</p> +<p>Which allows us to do something like this:</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>UsersNewRoute <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>Route<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> model<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> transaction <span style="color:#81a1c1">=</span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;store&#34;</span><span style="color:#eceff4">).</span>transaction<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">var</span> user <span style="color:#81a1c1">=</span> transaction<span style="color:#eceff4">.</span>createRecord<span style="color:#eceff4">(</span>App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">,</span> <span style="color:#eceff4">{});</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">return</span> user<span style="color:#eceff4">;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">},</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> events<span style="color:#81a1c1">:</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> createUser<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">(</span>user<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;transaction&#34;</span><span style="color:#eceff4">).</span>commit<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><p>Personally I use this when I only care about one record, but I know that +there might be other which are <code>dirty</code> and I don&rsquo;t want to commit those. +This happens almost every time you have two forms displayed at once.</p> + + + + + Ember.js: Router and Template Naming Convention + https://blog.jakuba.net/2013-02-01-ember-dot-js-router-and-template-naming-convention/ + Fri, 01 Feb 2013 19:43:00 +0000 + + https://blog.jakuba.net/2013-02-01-ember-dot-js-router-and-template-naming-convention/ + <p>Ever since the change to <code>resource</code> and <code>route</code> a lot of people are +confused about the meaning of the two and how they affect naming. Here&rsquo;s +the difference:</p> +<ul> +<li><code>resource</code> - a thing</li> +<li><code>route</code> - something to do with the thing</li> +</ul> +<p>Let&rsquo;s say we have a model <code>App.Post</code> and we want to show a list of posts +and a new post form. There are many ways you can go about this, so let&rsquo;s +start with the simplest.</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>Router<span style="color:#eceff4">.</span>map<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>resource<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;posts&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> path<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;/&#34;</span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>route<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;new&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> path<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;/new&#34;</span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><p>This would result in the following template structure</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span><span style="color:#eceff4">&lt;</span><span style="color:#81a1c1">script</span> <span style="color:#8fbcbb">type</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;text/x-handlebars&#34;</span> <span style="color:#8fbcbb">data-template-name</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;posts&#34;</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">...</span> list the posts +</span></span><span style="display:flex;"><span><span style="color:#eceff4">&lt;/</span><span style="color:#81a1c1">script</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">&lt;</span><span style="color:#81a1c1">script</span> <span style="color:#8fbcbb">type</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;text/x-handlebars&#34;</span> <span style="color:#8fbcbb">data-template-name</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;new&#34;</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">...</span> <span style="color:#81a1c1;font-weight:bold">new</span> post template +</span></span><span style="display:flex;"><span><span style="color:#eceff4">&lt;/</span><span style="color:#81a1c1">script</span><span style="color:#eceff4">&gt;</span> +</span></span></code></pre></div><p>With the following naming</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>PostsRoute +</span></span><span style="display:flex;"><span>PostsController +</span></span><span style="display:flex;"><span>PostsView +</span></span><span style="display:flex;"><span>NewRoute +</span></span><span style="display:flex;"><span>NewController +</span></span><span style="display:flex;"><span>NewView +</span></span></code></pre></div><p><a href="http://jsbin.com/ogorab/33/edit">Here&rsquo;s a JSBin</a></p> +<p>This is almost never useful, since you might have many <code>/new</code> actions +and you&rsquo;d need to scope them to the resource, which would be done as +follows</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>Router<span style="color:#eceff4">.</span>map<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>resource<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;posts&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> path<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;/&#34;</span> <span style="color:#eceff4">},</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>route<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;new&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> path<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;/new&#34;</span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><p>Here things get a little more complicated, since we&rsquo;re nesting something +inside the resource. This means that we&rsquo;ll end up with three templates +instead of two</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span><span style="color:#eceff4">&lt;</span><span style="color:#81a1c1">script</span> <span style="color:#8fbcbb">type</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;text/x-handlebars&#34;</span> <span style="color:#8fbcbb">data-template-name</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;posts&#34;</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1">&lt;</span>h1<span style="color:#81a1c1">&gt;</span>This is the outlet<span style="color:#81a1c1">&lt;</span><span style="color:#bf616a">/h1&gt;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">{{</span>outlet<span style="color:#eceff4">}}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">&lt;/</span><span style="color:#81a1c1">script</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">&lt;</span><span style="color:#81a1c1">script</span> <span style="color:#8fbcbb">type</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;text/x-handlebars&#34;</span> <span style="color:#8fbcbb">data-template-name</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;posts/index&#34;</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">...</span> list the posts +</span></span><span style="display:flex;"><span><span style="color:#eceff4">&lt;/</span><span style="color:#81a1c1">script</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">&lt;</span><span style="color:#81a1c1">script</span> <span style="color:#8fbcbb">type</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;text/x-handlebars&#34;</span> <span style="color:#8fbcbb">data-template-name</span><span style="color:#81a1c1">=</span><span style="color:#a3be8c">&#34;posts/new&#34;</span><span style="color:#eceff4">&gt;</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">...</span> <span style="color:#81a1c1;font-weight:bold">new</span> post template +</span></span><span style="display:flex;"><span><span style="color:#eceff4">&lt;/</span><span style="color:#81a1c1">script</span><span style="color:#eceff4">&gt;</span> +</span></span></code></pre></div><p>With the following naming</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>PostsRoute +</span></span><span style="display:flex;"><span>PostsController +</span></span><span style="display:flex;"><span>PostsView +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>PostsIndexRoute +</span></span><span style="display:flex;"><span>PostsIndexController +</span></span><span style="display:flex;"><span>PostsIndexView +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>PostsNewRoute +</span></span><span style="display:flex;"><span>PostsNewController +</span></span><span style="display:flex;"><span>PostsNewView +</span></span></code></pre></div><p><a href="http://jsbin.com/ogorab/34/edit">Here&rsquo;s a JSBin</a></p> +<p>This means whenever you create a resource it will create a brand new +namespace. That namespace will have an <code>{{outlet}}</code> which is named after the +resource and all of the child routes will be inserted into it.</p> +<p>There are many reasons behind it, but let&rsquo;s try another example which +will make it more obvious. We will add a <code>/:post_id</code> and +<code>/:post_id/edit</code> routes.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>Router<span style="color:#eceff4">.</span>map<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>resource<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;posts&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> path<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;/&#34;</span> <span style="color:#eceff4">},</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>resource<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;post&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> path<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;/:post_id&#34;</span> <span style="color:#eceff4">},</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>route<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;edit&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> path<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;/edit&#34;</span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>route<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;new&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> path<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;/new&#34;</span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><p>Additional to the routes in the previous example, this will give us</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// IMPORTANT - it&#39;s not PostsPostRoute, because `resource` +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// always creates a new namespace +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>PostRoute +</span></span><span style="display:flex;"><span>PostController +</span></span><span style="display:flex;"><span>PostView +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>PostIndexRoute +</span></span><span style="display:flex;"><span>PostIndexController +</span></span><span style="display:flex;"><span>PostIndexView +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>PostEditRoute +</span></span><span style="display:flex;"><span>PostEditController +</span></span><span style="display:flex;"><span>PostEditView +</span></span></code></pre></div><p>Templates are named accordingly <code>post</code>, <code>post.index</code> and <code>post.edit</code>, +<strong>there is nothing like <code>posts.post.index</code> or <code>posts.post</code> or +<code>posts.post.edit</code></strong>.</p> +<p><a href="http://jsbin.com/ogorab/35/edit">Here&rsquo;s a JSBin</a></p> +<p>But the problem is when we try to access the <code>App.Post</code> model from the +<code>post/index</code> or <code>post/edit</code> template. It is only available in the <code>post</code> +template with the outlet. Now why is that?</p> +<p>Since we are defining a <code>resource</code> it is expected that the child routes +will be related to that <code>resource</code>, that&rsquo;s why they don&rsquo;t need to load +it separately. They can access it from the parent <code>PostController</code> via +<code>needs</code> (<a href="http://darthdeus.github.com/blog/2013/01/27/controllers-needs-explained/">more about that can be found in this article</a></p> +<p><a href="http://jsbin.com/ogorab/44/edit">Here&rsquo;s a JSBin</a></p> +<p>This is the general pattern you would be using if you want to nest +everything. But what if you don&rsquo;t want to render <code>post</code> into the +<code>posts</code> outlet? Well nothing prevents you from defining the routes as +this.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>Router<span style="color:#eceff4">.</span>map<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>resource<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;posts&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> path<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;/&#34;</span> <span style="color:#eceff4">},</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>route<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;new&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> path<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;/new&#34;</span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>resource<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;post&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> path<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;/:post_id&#34;</span> <span style="color:#eceff4">},</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>route<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;edit&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> path<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;/edit&#34;</span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><p>What is the difference? The naming remains exactly the same as in the +previous example, even templates are named the same. But the <code>post</code> +template will be inserted into the <code>application</code> layout, not inside the +<code>posts</code> layout. This is the case when you want the detail <code>post</code> page to +replace the whole layout, instead of just showing it together with the +<code>posts</code> list.</p> +<p>I hope the examples will help you understanding how the v2 routes work, +since this is a completely essential part of Ember.js.</p> +<p>If you have any questions, leave them in the comments or tweet me +<a href="http://twitter.com/darthdeus">@darthdeus</a>.</p> + + + + + Ember.js: How to find a model by any attribute in Ember.js + https://blog.jakuba.net/2013-01-31-how-to-find-a-model-by-any-attribute-in-ember-dot-js/ + Thu, 31 Jan 2013 23:13:00 +0000 + + https://blog.jakuba.net/2013-01-31-how-to-find-a-model-by-any-attribute-in-ember-dot-js/ + <p>One of the common things people ask about Ember Data is how to find a +single record by it&rsquo;s attribute. This is because the current revision +(11) only offers three methods of fetching records</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">.</span>find<span style="color:#eceff4">(</span><span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// returns a single user record +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">.</span>find<span style="color:#eceff4">({</span> username<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;wycats&#34;</span> <span style="color:#eceff4">})</span> <span style="color:#616e87;font-style:italic">// returns a ManyArray +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">.</span>findQuery<span style="color:#eceff4">({</span> username<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;wycats&#34;</span> <span style="color:#eceff4">})</span> <span style="color:#616e87;font-style:italic">// same as the above +</span></span></span></code></pre></div><!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<p>If you want to search for a user by his username, you have two options</p> +<h2 id="using-find-with-_smart_-server-side">Using .find with <em>smart</em> server side</h2> +<p>The way <code>App.User.find(1)</code> works is that it does a request to +<code>/users/1</code>, which is expected to return just one record.</p> +<p>You could modify your server to accept both <code>username</code> and <code>id</code> on the +<code>/users/1</code> path, which would allow to do <code>App.User.find(&quot;wycats&quot;)</code>.</p> +<p>There&rsquo;s an issue with this though. If you load the same user via his +<code>username</code> and <code>id</code>, you&rsquo;ll end up with two records stored in the Ember +identity map.</p> +<p>Which basically means that if you try to retrieve all of the user +records, you will end up with that one user twice.</p> +<p>If you want to read more about this, <a href="https://github.com/emberjs/data/issues/571">checkout this GitHub +issue</a></p> +<h2 id="using-a-findquery">Using a findQuery</h2> +<p>This might not seem like the right solution at first, since it returns a +<code>DS.ManyArray</code> instead of just one record, but hang on.</p> +<p><code>DS.ManyArray</code> is a subclass of <code>DS.RecordArray</code>, which includes a +<code>DS.LoadPromise</code>.</p> +<p>To understand how <code>DS.LoadPromise</code> works, we need to understand what +promises are. <a href="https://gist.github.com/3889970">There&rsquo;s a great article about +that</a>, so I won&rsquo;t go into much detail.</p> +<p>Promise is basically an async monad (I guess that doesn&rsquo;t help, let&rsquo;s +try again).</p> +<p>Promise is something which allows you to return an object which wraps +around a value, even if you don&rsquo;t have the value yet. For example if +you&rsquo;re doing <code>App.User.findQuery</code>, you&rsquo;ll get back an empty +<code>DS.ManyArray</code> instantly.</p> +<p>It doesn&rsquo;t wait until the AJAX request is finished, it just returns the +empty array, which is populated with the data once the request finishes.</p> +<p>This works because Ember uses data bindings and will automagically +update all of the views once the data is loaded. And also because the +router will wait if it&rsquo;s model has a state <code>isLoading</code>. That way you +won&rsquo;t display a page which is half loaded.</p> +<h2 id="implementation">Implementation</h2> +<p>Now that we know we&rsquo;re getting a <code>DS.ManyArray</code>, we need to figure out a +way to make it represent only the value of it&rsquo;s first element, because +that&rsquo;s what we care about.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">var</span> users <span style="color:#81a1c1">=</span> App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">.</span>findQuery<span style="color:#eceff4">({</span> username<span style="color:#81a1c1">:</span> username <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>users<span style="color:#eceff4">.</span>one<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;didLoad&#34;</span><span style="color:#eceff4">,</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> users<span style="color:#eceff4">.</span>resolve<span style="color:#eceff4">(</span>users<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;firstObject&#34;</span><span style="color:#eceff4">));</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">return</span> users<span style="color:#eceff4">;</span> +</span></span></code></pre></div><p>You can see that we are returning the result of the <code>findQuery</code> +instantly, but we&rsquo;re also setting an asynchronous callback which +<strong>resolves the promise</strong> to the <code>firstObject</code> once it is loaded.</p> +<p>Another way you could read the <code>resolve(x)</code> is <em>from now you&rsquo;re +representing value <code>x</code></em>. Using this technique will work in all Ember, +because the data bindings will take care of everything. Always remember +that you don&rsquo;t need to worry about re-rendering your views, just change +the data and Ember will take care of the rest.</p> + + + + + Ember.js: Controller, ObjectController and ObjectProxy + https://blog.jakuba.net/2013-01-27-controller-objectcontroller-and-objectproxy/ + Sun, 27 Jan 2013 19:24:00 +0000 + + https://blog.jakuba.net/2013-01-27-controller-objectcontroller-and-objectproxy/ + <p>When you first come to Ember, you&rsquo;ll soon stumble upon three things:</p> +<ul> +<li><code>Ember.Controller</code></li> +<li><code>Ember.ObjectController</code></li> +<li><code>Ember.ArrayController</code></li> +</ul> +<p>For some people (including me) it is not very clear what&rsquo;s the +difference between the first two.</p> +<p><code>Ember.Controller</code> is just a plain implementation of +<code>Ember.ControllerMixin</code>, while <code>Ember.ObjectController</code> is a subclass of +<code>Ember.ObjectProxy</code>. This is a huge difference! Let&rsquo;s take a look at how +<code>Ember.ObjectProxy</code> works, and as always starting with a code sample +(<a href="https://github.com/emberjs/ember.js/blob/master/packages/ember-runtime/lib/system/object_proxy.js#L35-L50">taken from the excellent source code documentation</a>).</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>object <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span><span style="color:#81a1c1">Object</span><span style="color:#eceff4">.</span>create<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> name<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;foo&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>proxy <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>ObjectProxy<span style="color:#eceff4">.</span>create<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> content<span style="color:#81a1c1">:</span> object +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// Access and change existing properties +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>proxy<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;name&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; &#34;foo&#34; +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>proxy<span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;name&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;bar&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>object<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;name&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; &#34;bar&#34; +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// Create new &#34;description&#34; property on `object` +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>proxy<span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;description&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;baz&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>object<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;description&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; &#34;baz&#34; +</span></span></span></code></pre></div><p>There is really no magic. In the basic usage, <code>Ember.ObjectProxy</code> will +delegate all of it&rsquo;s unknown properties to the <code>content</code> object, with +one exception.</p> +<p>If we try to set a new property on a proxy while it&rsquo;s content is +undefined, we will get an exception.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>proxy <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>ObjectProxy<span style="color:#eceff4">.</span>create<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span>proxy<span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;foo&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;bar&#34;</span><span style="color:#eceff4">);</span> <span style="color:#616e87;font-style:italic">// raises the following exception +</span></span></span></code></pre></div><pre tabindex="0"><code>Cannot delegate set(&#39;foo&#39;, bar) to the &#39;content&#39; property +of object proxy &lt;Ember.ObjectProxy:ember420&gt;: its &#39;content&#39; is undefined. +</code></pre><p>I&rsquo;ve stumbled upon this in one scenario, where I didn&rsquo;t set content for +my <code>ObjectController</code>, but I tried to modify one of it&rsquo;s properties. +Raising the exception is a good example of failing fast, rather than +silently swallowing errors.</p> +<p>This being said you should almost always use <code>Ember.ObjectController</code> +over <code>Ember.Controller</code>, unless you know what you&rsquo;re doing :)</p> + + + + + Ember.js: State Manager and Friends - part 1 + https://blog.jakuba.net/2013-01-27-state-manager-and-friends/ + Sun, 27 Jan 2013 19:23:00 +0000 + + https://blog.jakuba.net/2013-01-27-state-manager-and-friends/ + <p>Since state management is such a huge part of Ember.js it desrves a +dedicated article. I&rsquo;m not going to explain the old router which used +<code>Ember.StateManager</code> to do it&rsquo;s bidding. Those days are over and we +should all be moving towards the v2 router (or v2.2 so to speak). +Instead we&rsquo;re going to go deep into the <code>Ember.StateManager</code>.</p> +<p>In the general concept, state manager is basically some object which +manages states and the transitions between them, thus representing a +finite state machine.</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<p>Let&rsquo;s say we have a <code>Post</code> which can be in two states, <code>draft</code> and +<code>published</code>. It begins it&rsquo;s life as a <code>draft</code> and when we <code>publish</code> it, +it should send out a notification email. The way Ember would handle this +is that it would assign a <code>Ember.StateManager</code> instance to the <code>Post</code> +instance and have that manage it&rsquo;s state (that&rsquo;s not exactly true in +Ember Data, but we&rsquo;ll get into that).</p> +<p>For now let&rsquo;s just say that this is the code we have</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>PostManager <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>StateManager<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> states<span style="color:#81a1c1">:</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> draft<span style="color:#81a1c1">:</span> Ember<span style="color:#eceff4">.</span>State<span style="color:#eceff4">.</span>create<span style="color:#eceff4">(),</span> +</span></span><span style="display:flex;"><span> published<span style="color:#81a1c1">:</span> Ember<span style="color:#eceff4">.</span>State<span style="color:#eceff4">.</span>create<span style="color:#eceff4">()</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>Post <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span><span style="color:#81a1c1">Object</span><span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> title<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">null</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> init<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;stateManager&#34;</span><span style="color:#eceff4">,</span> PostManager<span style="color:#eceff4">.</span>create<span style="color:#eceff4">());</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>_super<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><p>This gives us a really basic implementation. I&rsquo;m setting the +<code>stateManager</code> property in the <code>init</code> function to avoid sharing the +instance across multiple <code>Post</code> instances. I&rsquo;ll explain this in a +followup article, for now just remember that if you need to set a +property to an object instance, you have to do that in the <code>init</code> +function, not directly like <code>stateManager: PostManager.create()</code>.</p> +<p>OK, we are now ready to list all of the states a <code>Post</code> can have.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>post <span style="color:#81a1c1">=</span> Post<span style="color:#eceff4">.</span>create<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span>post<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;stateManager.states&#34;</span><span style="color:#eceff4">);</span> <span style="color:#616e87;font-style:italic">// =&gt; { draft: ..., published: ... } +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span>post<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;stateManager.currentState&#34;</span><span style="color:#eceff4">);</span> <span style="color:#616e87;font-style:italic">// =&gt; null +</span></span></span></code></pre></div><p>We forgot to say which of the states should be the default. Let&rsquo;s +do that.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>PostManager <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>StateManager<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> initialState<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;draft&#34;</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> states<span style="color:#81a1c1">:</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> draft<span style="color:#81a1c1">:</span> Ember<span style="color:#eceff4">.</span>State<span style="color:#eceff4">.</span>create<span style="color:#eceff4">(),</span> +</span></span><span style="display:flex;"><span> published<span style="color:#81a1c1">:</span> Ember<span style="color:#eceff4">.</span>State<span style="color:#eceff4">.</span>create<span style="color:#eceff4">()</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><p>From now every single post we create will be a <code>draft</code></p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>post <span style="color:#81a1c1">=</span> Post<span style="color:#eceff4">.</span>create<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span>post<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;stateManager.currentState.name&#34;</span><span style="color:#eceff4">);</span> <span style="color:#616e87;font-style:italic">// =&gt; &#34;draft&#34; +</span></span></span></code></pre></div><p>And we can also make it transition into another state</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>post <span style="color:#81a1c1">=</span> Post<span style="color:#eceff4">.</span>create<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span>post<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;stateManager&#34;</span><span style="color:#eceff4">).</span>transitionTo<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;published&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>post<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;stateManager.currentState.name&#34;</span><span style="color:#eceff4">);</span> <span style="color:#616e87;font-style:italic">// =&gt; &#34;published&#34; +</span></span></span></code></pre></div><p>But <code>Ember.StateManager</code> can do more than that. We can hook into both +<code>enter</code> and <code>exit</code> events on each state and do some magic! Let&rsquo;s +redefine our state manager as this</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>PostManager <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>StateManager<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> initialState<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;draft&#34;</span><span style="color:#eceff4">,</span> +</span></span><span style="display:flex;"><span> states<span style="color:#81a1c1">:</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> draft<span style="color:#81a1c1">:</span> Ember<span style="color:#eceff4">.</span>State<span style="color:#eceff4">.</span>create<span style="color:#eceff4">(),</span> +</span></span><span style="display:flex;"><span> published<span style="color:#81a1c1">:</span> Ember<span style="color:#eceff4">.</span>State<span style="color:#eceff4">.</span>create<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> enter<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> console<span style="color:#eceff4">.</span>log<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;post was published&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">})</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>post <span style="color:#81a1c1">=</span> Post<span style="color:#eceff4">.</span>create<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span>post<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;stateManager&#34;</span><span style="color:#eceff4">).</span>transitionTo<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;published&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// console prints &#34;post was published&#34; +</span></span></span></code></pre></div><p>Understanding how this class works is essential for any Ember developer, +as it is being used in almost every part of the framework. We&rsquo;ll take at +some specific examples in the second part of this artcile.</p> + + + + + Ember.js: Concatenated Properties + https://blog.jakuba.net/2013-01-27-concatenated-properties/ + Sun, 27 Jan 2013 18:18:00 +0000 + + https://blog.jakuba.net/2013-01-27-concatenated-properties/ + <p>As some of you might now, Ember provides you with something called +<em>concatenated property</em>. Their main use case is internal, which means +you are unlikely to have the need to use them in your own application. +There are some places in Ember where you might be surprised by how +things behave and this might be one of those. Let&rsquo;s start with an +example.</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>UserView <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>View<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> classNames<span style="color:#81a1c1">:</span> <span style="color:#eceff4">[</span><span style="color:#a3be8c">&#34;user&#34;</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>UserView<span style="color:#eceff4">.</span>create<span style="color:#eceff4">().</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;classNames&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; [&#34;ember-view&#34;, &#34;user&#34;] +</span></span></span></code></pre></div><p>Now you might be asking, where is the <code>&quot;ember-view&quot;</code> coming from? Time +for another example</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>DetailUserView <span style="color:#81a1c1">=</span> App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> classNames<span style="color:#81a1c1">:</span> <span style="color:#eceff4">[</span><span style="color:#a3be8c">&#34;more&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;detail&#34;</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>DetailUserView<span style="color:#eceff4">.</span>create<span style="color:#eceff4">().</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;classNames&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; [&#34;ember-view&#34;, &#34;user&#34;, &#34;more&#34;, &#34;detail&#34;] +</span></span></span></code></pre></div><p>This must be some sorcery! It seems that <code>classNames</code> aren&rsquo;t overwritten +in the subclass, but rather concatenated to the superclass&rsquo; value of +that property. This works even when you overwrite it in an instance.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>Ember<span style="color:#eceff4">.</span>View<span style="color:#eceff4">.</span>create<span style="color:#eceff4">({</span> classNames<span style="color:#81a1c1">:</span> <span style="color:#eceff4">[</span><span style="color:#a3be8c">&#34;cat&#34;</span><span style="color:#eceff4">]</span> <span style="color:#eceff4">}).</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;classNames&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; [&#34;ember-view&#34;, &#34;cat&#34;] +</span></span></span></code></pre></div><p>A simple glance at the <a href="https://github.com/emberjs/ember.js/blob/master/packages/ember-views/lib/views/view.js#L756"><code>Ember.View</code></a> source code reveals it&rsquo;s secrets</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>Ember<span style="color:#eceff4">.</span>View <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>CoreView<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> concatenatedProperties<span style="color:#81a1c1">:</span> <span style="color:#eceff4">[</span><span style="color:#a3be8c">&#39;classNames&#39;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#39;classNameBindings&#39;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#39;attributeBindings&#39;</span><span style="color:#eceff4">],</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// more stuff +</span></span></span></code></pre></div><p>If this still doesn&rsquo;t make any sense to you, just go take a look at <a href="https://github.com/emberjs/ember.js/blob/master/packages/ember-metal/tests/mixin/concatenatedProperties_test.js">the +tests for concatenated properties</a>.</p> + + + + + Ember.js: Ember Data in Depth + https://blog.jakuba.net/2013-01-27-ember-data-in-depth/ + Sun, 27 Jan 2013 13:52:00 +0000 + + https://blog.jakuba.net/2013-01-27-ember-data-in-depth/ + <p>This is a guide explaining how Ember Data works internaly. My initial +motivation for writing this is to understand Ember better myself. I&rsquo;ve +found that every time I understand something about how Ember works, it +improves my application code.</p> +<h2 id="main-parts">Main parts</h2> +<p>First we need to understand what are the main concepts. Let&rsquo;s start with +a simple example.</p> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>User <span style="color:#81a1c1">=</span> DS<span style="color:#eceff4">.</span>Model<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> username<span style="color:#81a1c1">:</span> DS<span style="color:#eceff4">.</span>attr<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;string&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><p>Let&rsquo;s dive deep into this. There are four important concepts, two of +which are basic Ember.js and we&rsquo;re going to skip them</p> +<ul> +<li><code>App.User</code> represents a <code>User</code> class in the <code>App</code> namespace</li> +<li><code>username</code> represents a property on the <code>User</code> class</li> +</ul> +<p>These are the basics and you should be familiar with them to understand +the rest of this guide. Next we have <code>DS.Model</code> and <code>DS.attr</code>:</p> +<h2 id="dsmodel-and-dsattr">DS.Model and DS.attr</h2> +<p><code>DS.Model</code> is one of the core concepts in Ember Data and it represents a +single <em>resource</em>. Models can have relationships with other models, +similar to how you&rsquo;d model your data in a relational database. But let&rsquo;s +ignore that for now.</p> +<p><code>DS.Model</code> is both a state machine and a promise. If you don&rsquo;t +understand what promises are, please take a look at <a href="https://gist.github.com/3889970">this awesome +article</a> which explains them in depth.</p> +<p>State machines are used throughout Ember and they basically represent something <em>which can have multiple states and can transition between the states</em>. For example <code>DS.Model</code> can have the following states (<em><a href="http://emberjs.com/guides/models/model-lifecycle/">taken from the official Ember guide</a></em>):</p> +<ul> +<li><code>isLoaded</code> - The adapter has finished retrieving the current state of the record from its backend.</li> +<li><code>isDirty</code> - The record has local changes that have not yet been saved by the adapter. This includes records that have been created (but not yet saved) or deleted.</li> +<li><code>isSaving</code> - The record has been sent to the adapter to have its changes saved to the backend, but the adapter has not yet confirmed that the changes were successful.</li> +<li><code>isDeleted</code> - The record was marked for deletion. When <code>isDeleted</code> is true and <code>isDirty</code> is <code>true</code>, the record is deleted locally but the deletion was not yet persisted. When <code>isSaving</code> is true, the change is in-flight. When both <code>isDirty</code> and <code>isSaving</code> are <code>false</code>, the change has been saved.</li> +<li><code>isError</code> - The adapter reported that it was unable to save local changes to the backend. This may also result in the record having its <code>isValid</code> property become false if the adapter reported that server-side validations failed.</li> +<li><code>isNew</code> - The record was created locally and the adapter did not yet report that it was successfully saved. +<code>isValid</code> No client-side validations have failed and the adapter did not report any server-side validation failures.</li> +</ul> +<p>We can also bind to these with event handlers, which will be explained later, but for now let&rsquo;s just list them:</p> +<ul> +<li><code>didLoad</code></li> +<li><code>didCreate</code></li> +<li><code>didUpdate</code></li> +<li><code>didDelete</code></li> +<li><code>becameError</code></li> +<li><code>becameInvalid</code></li> +</ul> +<p><em><a href="https://github.com/emberjs/data/blob/f274153754cb8b629cd98fc6c590f18bc8ee3ff6/packages/ember-data/lib/system/model/states.js#L223-L245">I would also encourage you to go take a look at the source documentation on GitHub</a></em></p> +<p>It is important for us to understand what each state means, because they +can affect how our application behaves. For example if we try to modify +a record which is already being saved, we will get an exception saying +something like this</p> +<pre tabindex="0"><code>Attempted to handle event `willSetProperty` on &lt;App.User:ember1144:null&gt; +while in state rootState.loaded.created.inFlight. Called with +{reference: [object Object], store: &lt;App.Store:ember313&gt;, name: username} +</code></pre><p>The important part here is the <code>rootState.loaded.created.inFlight</code>. If +we look at <a href="https://github.com/emberjs/data/blob/f274153754cb8b629cd98fc6c590f18bc8ee3ff6/packages/ember-data/lib/system/model/states.js#L254-L261">the source of <code>DirtyState</code></a>, we can see what this means</p> +<blockquote> +<p>Dirty states have three child states:</p> +<ul> +<li><code>uncommitted</code>: the store has not yet handed off the record to be saved.</li> +<li><code>inFlight</code>: the store has handed off the record to be saved, but the adapter has not yet acknowledged success.</li> +<li><code>invalid</code>: the record has invalid information and cannot be send to the adapter yet.</li> +</ul> +</blockquote> +<p>Let&rsquo;s go through the record lifecycle and observe it&rsquo;s state. We can do +this by doing <code>.get(&quot;stateManager.currentState.name&quot;)</code></p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>user <span style="color:#81a1c1">=</span> App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">.</span>find<span style="color:#eceff4">(</span><span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;isLoaded&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; true +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;isDirty&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; false +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;stateManager.currentState.name&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; loaded +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span>user<span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;username&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;wycats&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;isLoaded&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; true +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;isDirty&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; true, which means comitting the transaction will save the record +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;stateManager.currentState.name&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; uncommitted +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;transaction&#34;</span><span style="color:#eceff4">).</span>commit<span style="color:#eceff4">()</span> +</span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// while the record is being saved +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;stateManager.currentState.name&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; inFlight +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;isSaving&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; true +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">// after the record was saved +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;stateManager.currentState.name&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; saved +</span></span></span></code></pre></div><h2 id="transactions-and-commit">Transactions and <code>commit()</code></h2> +<p>In the previous example, we&rsquo;ve used <code>get(&quot;transaction&quot;).commit()</code> to +persist the changes to the server. <code>.commit()</code> will take all <code>dirty</code> +records in the transaction and persiste them to the server.</p> +<p>A record becomes dirty whenever one of it&rsquo;s attributes change. For +example</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>user <span style="color:#81a1c1">=</span> App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">.</span>find<span style="color:#eceff4">(</span><span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;isDirty&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; false +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>user<span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;username&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;wycats&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;isDirty&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; true +</span></span></span></code></pre></div><p>If we create a new record, it will be dirty by default</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>user <span style="color:#81a1c1">=</span> App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">.</span>createRecord<span style="color:#eceff4">()</span> +</span></span><span style="display:flex;"><span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;isDirty&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; true +</span></span></span></code></pre></div><p><a href="https://github.com/emberjs/data/pull/646">Currently there&rsquo;s a regression</a> +that we change an attribute to something else, and then back to the +original value, the record will be marked as dirty.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>user <span style="color:#81a1c1">=</span> App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">.</span>find<span style="color:#eceff4">(</span><span style="color:#b48ead">1</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span>originalUsername <span style="color:#81a1c1">=</span> user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;username&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;isDirty&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; false +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>user<span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;username&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;wycats&#34;</span><span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;isDirty&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; true +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>user<span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;username&#34;</span><span style="color:#eceff4">,</span> originalUsername<span style="color:#eceff4">)</span> +</span></span><span style="display:flex;"><span>user<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;isDirty&#34;</span><span style="color:#eceff4">)</span> <span style="color:#616e87;font-style:italic">// =&gt; true, even though it should be false +</span></span></span></code></pre></div><p>But let&rsquo;s hope this will be fixed soon.</p> +<h2 id="transactions">Transactions</h2> +<p>Until now we assumed that there is some <em>global</em> transaction which is +the same for every single model. But this doesn&rsquo;t have to be true. We +can create our own transactions and manage them at our will.</p> +<p>I recommend you take a look at <a href="https://github.com/emberjs/data/blob/master/packages/ember-data/tests/integration/transactions/basic_test.js">the tests for transactions in Ember Data +repository</a>. +They basically show all of the scenarios which you can encounter. For +example</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>transaction <span style="color:#81a1c1">=</span> store<span style="color:#eceff4">.</span>transaction<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span>record <span style="color:#81a1c1">=</span> transaction<span style="color:#eceff4">.</span>createRecord<span style="color:#eceff4">(</span>App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">,</span> <span style="color:#eceff4">{});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>transaction<span style="color:#eceff4">.</span>commit<span style="color:#eceff4">();</span> <span style="color:#616e87;font-style:italic">// this will save the record to the server +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span>record<span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;foo&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;bar&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>transaction<span style="color:#eceff4">.</span>commit<span style="color:#eceff4">();</span> <span style="color:#616e87;font-style:italic">// nothing is committed here, because the record +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#616e87;font-style:italic">// is removed from the transaction when it is saved +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> +</span></span><span style="display:flex;"><span>store<span style="color:#eceff4">.</span>commit<span style="color:#eceff4">();</span> <span style="color:#616e87;font-style:italic">// this will save the record properly +</span></span></span></code></pre></div><p>We can also add a record to a transaction, which will remove it from the +global transaction. Important thing to note here is that +<a href="https://github.com/emberjs/data/blob/master/packages/ember-data/lib/system/store.js#L127-L129"><code>store.transaction()</code></a> +<strong>always returns a new transaction</strong>.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>user <span style="color:#81a1c1">=</span> App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">.</span>find<span style="color:#eceff4">(</span><span style="color:#b48ead">1</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>transaction <span style="color:#81a1c1">=</span> store<span style="color:#eceff4">.</span>transaction<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span>transaction<span style="color:#eceff4">.</span>add<span style="color:#eceff4">(</span>user<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>user<span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;username&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;wycats&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>store<span style="color:#eceff4">.</span>commit<span style="color:#eceff4">();</span> <span style="color:#616e87;font-style:italic">// nothing happens +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>transaction<span style="color:#eceff4">.</span>commit<span style="color:#eceff4">();</span> <span style="color:#616e87;font-style:italic">// user is saved +</span></span></span></code></pre></div><p>Same goes for deleting records</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>user <span style="color:#81a1c1">=</span> App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">.</span>find<span style="color:#eceff4">(</span><span style="color:#b48ead">1</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>transaction <span style="color:#81a1c1">=</span> store<span style="color:#eceff4">.</span>transaction<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span>transaction<span style="color:#eceff4">.</span>add<span style="color:#eceff4">(</span>user<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>user<span style="color:#eceff4">.</span>deleteRecord<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>store<span style="color:#eceff4">.</span>commit<span style="color:#eceff4">();</span> <span style="color:#616e87;font-style:italic">// nothing happens +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span>transaction<span style="color:#eceff4">.</span>commit<span style="color:#eceff4">();</span> <span style="color:#616e87;font-style:italic">// user is deleted +</span></span></span></code></pre></div><p>We can also remove a record from a transaction</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>user <span style="color:#81a1c1">=</span> App<span style="color:#eceff4">.</span>User<span style="color:#eceff4">.</span>find<span style="color:#eceff4">(</span><span style="color:#b48ead">1</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>transaction <span style="color:#81a1c1">=</span> store<span style="color:#eceff4">.</span>transaction<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>transaction<span style="color:#eceff4">.</span>add<span style="color:#eceff4">(</span>user<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span>transaction<span style="color:#eceff4">.</span>remove<span style="color:#eceff4">(</span>user<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>user<span style="color:#eceff4">.</span>set<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;name&#34;</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#34;wycats&#34;</span><span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>transaction<span style="color:#eceff4">.</span>commit<span style="color:#eceff4">();</span> <span style="color:#616e87;font-style:italic">// nothing happens +</span></span></span></code></pre></div><p>One scenario when transactions can be useful is when you just need to +change one record, without affecting changes to other records. You can +put that change in a separate transaction, instead of just doing +<code>store.commit()</code>.</p> +<p>Important thing to note here is that there&rsquo;s a <code>defaultTransaction</code> for +the store to which you can get via <code>store.get(&quot;defaultTransaction&quot;)</code>. +This is where all of the records are placed, unless you explicitly +create a new transaction and assign a record to it.</p> +<p>These two are completely equivalent</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>store<span style="color:#eceff4">.</span>commit<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span>store<span style="color:#eceff4">.</span>get<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;defaultTransaction&#34;</span><span style="color:#eceff4">).</span>commit<span style="color:#eceff4">();</span> +</span></span></code></pre></div><p>Just take a look at how <code>store.commit()</code> is defined</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>commit<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> get<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#39;defaultTransaction&#39;</span><span style="color:#eceff4">).</span>commit<span style="color:#eceff4">();</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">},</span> +</span></span></code></pre></div><h2 id="commit"><code>commit()</code></h2> +<p>Now that we understand how transactions work, let&rsquo;s dig deep into +<code>store.commit()</code>. First thing we need to understand here is that Ember +Transactions use this thing called <code>bucket</code> to store records with +various states in. This is first initialized in the <a href="https://github.com/emberjs/data/blob/master/packages/ember-data/lib/system/transaction.js#L91-L101"><code>init</code> method of +<code>DS.Transaction</code></a></p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>init<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> set<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#39;buckets&#39;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> clean<span style="color:#81a1c1">:</span> Ember<span style="color:#eceff4">.</span>OrderedSet<span style="color:#eceff4">.</span>create<span style="color:#eceff4">(),</span> +</span></span><span style="display:flex;"><span> created<span style="color:#81a1c1">:</span> Ember<span style="color:#eceff4">.</span>OrderedSet<span style="color:#eceff4">.</span>create<span style="color:#eceff4">(),</span> +</span></span><span style="display:flex;"><span> updated<span style="color:#81a1c1">:</span> Ember<span style="color:#eceff4">.</span>OrderedSet<span style="color:#eceff4">.</span>create<span style="color:#eceff4">(),</span> +</span></span><span style="display:flex;"><span> deleted<span style="color:#81a1c1">:</span> Ember<span style="color:#eceff4">.</span>OrderedSet<span style="color:#eceff4">.</span>create<span style="color:#eceff4">(),</span> +</span></span><span style="display:flex;"><span> inflight<span style="color:#81a1c1">:</span> Ember<span style="color:#eceff4">.</span>OrderedSet<span style="color:#eceff4">.</span>create<span style="color:#eceff4">()</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> set<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">,</span> <span style="color:#a3be8c">&#39;relationships&#39;</span><span style="color:#eceff4">,</span> Ember<span style="color:#eceff4">.</span>OrderedSet<span style="color:#eceff4">.</span>create<span style="color:#eceff4">());</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span> +</span></span></code></pre></div><p>Each bucket represents one state in which a record can possibly be. +These are used in many different places in the transaction, and every +time a method changes it&rsquo;s state, it will be moved to a corresponding +bucket</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>recordBecameDirty<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">(</span>bucketType<span style="color:#eceff4">,</span> record<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>removeFromBucket<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#39;clean&#39;</span><span style="color:#eceff4">,</span> record<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>addToBucket<span style="color:#eceff4">(</span>bucketType<span style="color:#eceff4">,</span> record<span style="color:#eceff4">);</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">},</span> +</span></span></code></pre></div><p><strong>More content will be coming soon</strong></p> + + + + + Ember.js: Controller's Needs Explained + https://blog.jakuba.net/2013-01-27-controllers-needs-explained/ + Sun, 27 Jan 2013 11:53:00 +0000 + + https://blog.jakuba.net/2013-01-27-controllers-needs-explained/ + <p>Since the v2 router came it became clear that using global singleton +controllers like <code>App.userController = App.UserController.create()</code> is +not the way to go. This prevents us from doing a simple binding like</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>UserController <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>ObjectController<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> accountsBinding<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;App.accountsController.content&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">})</span> +</span></span></code></pre></div><!-- raw HTML omitted --> +<!-- raw HTML omitted --> +<p>There is no need or even possibility to manage the controller instances +with the new router though. It will create the instance for us. One way +we can use this is with <code>this.controllerFor</code>, which can be used inside +of a route.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>UserRoute <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>Route<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> setupController<span style="color:#81a1c1">:</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">(</span>controller<span style="color:#eceff4">,</span> model<span style="color:#eceff4">)</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#616e87;font-style:italic">// some magic with `this.controllerFor(&#34;user&#34;)` +</span></span></span><span style="display:flex;"><span><span style="color:#616e87;font-style:italic"></span> <span style="color:#eceff4">}</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">})</span> +</span></span></code></pre></div><p>but since this method is only available on the route and not inside a +controller, it wasn&rsquo;t very pleasant to specify dependencies (or needs) +between controllers. Which is exactly where needs come in and solve the +issue</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>UserController <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>ObjectController<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> needs<span style="color:#81a1c1">:</span> <span style="color:#eceff4">[</span><span style="color:#a3be8c">&#34;foo&#34;</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><p>this will give you the opportunity to call <code>controllers.foo</code> on the +<code>App.UserController</code> instance and get back an instance of +<code>App.FooController</code>. You could even (ab)use that in the templates like +this</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span><span style="color:#616e87;font-style:italic">&lt;!-- inside `users` template --&gt;</span> +</span></span><span style="display:flex;"><span>{% raw %}{{controllers.foo}}{% endraw %} +</span></span></code></pre></div><h2 id="needs-vs-routing">Needs vs routing</h2> +<p>Needs become incredibly useful when you have nested routes, for example</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>Router<span style="color:#eceff4">.</span>map<span style="color:#eceff4">(</span><span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>resource<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;post&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> path<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;/posts/:post_id&#34;</span> <span style="color:#eceff4">},</span> <span style="color:#81a1c1;font-weight:bold">function</span><span style="color:#eceff4">()</span> <span style="color:#eceff4">{</span> +</span></span><span style="display:flex;"><span> <span style="color:#81a1c1;font-weight:bold">this</span><span style="color:#eceff4">.</span>route<span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;edit&#34;</span><span style="color:#eceff4">,</span> <span style="color:#eceff4">{</span> path<span style="color:#81a1c1">:</span> <span style="color:#a3be8c">&#34;/edit&#34;</span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span> <span style="color:#eceff4">});</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">});</span> +</span></span></code></pre></div><p>In this case we will get <code>post</code>, <code>post.index</code> and <code>post.edit</code>. If you go +to <code>/posts/1</code> you expect to get <code>post.index</code> template, which is true, +but the context (or model, or content) is being set on the +<code>PostController</code>, not on <code>PostIndexController</code>.</p> +<p>When you think about it it does make sense, because the <code>resource</code> is +basically shared between <code>post.index</code> and <code>post.edit</code>, that&rsquo;s why it is +fetched and stored in their parent. Let&rsquo;s go through this in detail:</p> +<ul> +<li>visit <code>/posts/1</code></li> +<li>router basically does <code>App.Post.find(1)</code> <strong>and assigns that to the +content of <code>PostController</code></strong></li> +<li>template <code>post</code> is rendered</li> +<li>template <code>post.index</code> is rendered in <code>post</code>&rsquo;s outlet</li> +</ul> +<p>and when you transition to <code>/posts/1/edit</code>, the only thing that changes +is the leaf route, you still keep the same <code>App.Post</code> model, because it +belongs to the parent <code>PostRoute</code>, not to the leaf <code>PostIndexRoute</code>. But +this has a drawback. You&rsquo;re not able to directly access the content from +the <code>post.index</code> template, since it doesn&rsquo;t belong to it&rsquo;s controller. +That&rsquo;s where needs come in.</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>App<span style="color:#eceff4">.</span>PostIndexController <span style="color:#81a1c1">=</span> Ember<span style="color:#eceff4">.</span>ObjectController<span style="color:#eceff4">.</span>extend<span style="color:#eceff4">({</span> +</span></span><span style="display:flex;"><span> needs<span style="color:#81a1c1">:</span> <span style="color:#eceff4">[</span><span style="color:#a3be8c">&#34;post&#34;</span><span style="color:#eceff4">]</span> +</span></span><span style="display:flex;"><span><span style="color:#eceff4">})</span> +</span></span></code></pre></div><p>and in the <code>post/index</code> template, you can access the content like this</p> +<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>{% raw %}{{controllers.post.content}}{% endraw %} +</span></span></code></pre></div><p>By specifying the need Ember will make sure that it gives you the right +<code>PostController</code> instance with it&rsquo;s content set to the right value.</p> + + + + +