<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Derp</title>
    <description>The latest articles on DEV Community by Derp (@derp).</description>
    <link>https://dev.to/derp</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F660836%2Fc1514bfe-15d3-431c-9c14-f1d752c2dd7b.jpg</url>
      <title>DEV Community: Derp</title>
      <link>https://dev.to/derp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/derp"/>
    <language>en</language>
    <item>
      <title>Parser combinators in typescript with parser-ts</title>
      <dc:creator>Derp</dc:creator>
      <pubDate>Tue, 31 Jan 2023 15:32:03 +0000</pubDate>
      <link>https://dev.to/derp/parser-combinators-in-typescript-with-parser-ts-part-1-46o3</link>
      <guid>https://dev.to/derp/parser-combinators-in-typescript-with-parser-ts-part-1-46o3</guid>
      <description>&lt;p&gt;Consider the following strings&lt;br&gt;
"13:15"&lt;br&gt;
"1:15pm"&lt;br&gt;
"quarter past 1pm"&lt;/p&gt;

&lt;p&gt;These may be just strings to a computer but to a human, we can see that they all represent a time. Furthermore, we see that there is some structure to these strings. So whereas “quarter past 1pm” makes sense as a time. “Foohoogablahblahl” does not.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgw8hfpriamafb81oa9ob.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgw8hfpriamafb81oa9ob.png" alt="Alien saying " width="705" height="666"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now our first instinct might be reach for regex to parse these strings and extract the data out of them, but I'd advise against it. We will solve this problem with &lt;a href="https://en.wikipedia.org/wiki/Parser_combinator" rel="noopener noreferrer"&gt;parser combinators&lt;/a&gt; using the &lt;a href="https://gcanti.github.io/parser-ts/" rel="noopener noreferrer"&gt;parser-ts&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;Let's begin with the first example "13:15" which is the time in 24 hour format. Upon closer examination, we see that it is comprised of three parts &amp;lt;hours&amp;gt; &amp;lt;:&amp;gt; &amp;lt;minutes&amp;gt; each with its own set of rules.&lt;/p&gt;

&lt;p&gt;Taking a look at the &amp;lt;hours&amp;gt; component, we know that there are some rules. First, it must be a number and that number must be between 0 &amp;amp; 23. So to begin with, we reach for the &lt;a href="https://gcanti.github.io/parser-ts/modules/string.ts.html#int" rel="noopener noreferrer"&gt;int parser&lt;/a&gt; from the &lt;code&gt;parser-ts/lib/string&lt;/code&gt; module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;parser-ts/lib/code-frame&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;parser-ts/lib/string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;14&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;//[1] Right 14&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;asdf4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;//[2] Left "Expected: an integer"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;14aaaaa&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;//[3] Right 14&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break this down. On line [1], we ran the parser on the string "14" and we got back a &lt;a href="https://gcanti.github.io/fp-ts/modules/Either.ts.html" rel="noopener noreferrer"&gt;Right&lt;/a&gt; instance containing the number 14. On line [2], we see that if the int parser is unable to extract out a number, we error out with a Left instance containing a helpful error message. On line [3], we see that we succeed in extracting out the number 14 and we abandon the rest of the string.&lt;/p&gt;

&lt;p&gt;Phew, that was a lot, however we aren't done yet because if we try to do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;29&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Right 29&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We succeed with the number 29 which isn't what we want because there isn't a 29th hour in 24 hour format. To solve this, we reach for our first combinator &lt;a href="https://gcanti.github.io/parser-ts/modules/Parser.ts.html#filter" rel="noopener noreferrer"&gt;filter&lt;/a&gt;. Filter allows us to pass in a predicate so that we can filter out our invalid values. After this, we finally have our 24 hours parser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isValid24Hour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hours24Parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isValid24Hour&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;24 hour clock hours must be between 0 &amp;amp; 23&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours24Parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;14&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Right 14&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours24Parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;32&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Left "24 hour clock hours must be between 0 &amp;amp; 23"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nice! Next we need our colon parser which matches just the ":" character.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;colonParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we apply a similar approach to the hours24Parser for our minutes parser&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isValidMinute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minutesParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isValidMinute&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Minutes must be between 0 &amp;amp; 59&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this stage, we have our &lt;code&gt;hours24Parser&lt;/code&gt;, our &lt;code&gt;colonParser&lt;/code&gt;and our &lt;code&gt;minutesParser&lt;/code&gt;. So the next challenge is to figure out a way to mash all three of these together. Now Parsers are monads which means that we can chain them together. To make life a bit simpler, we will be using the &lt;code&gt;bind&lt;/code&gt; and &lt;code&gt;bindTo&lt;/code&gt; convenience methods to store our extracted data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;time24hoursParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;hours24Parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bindTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hours&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// store hours into an object with key 'hours'&lt;/span&gt;
  &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chainFirst&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;colonParser&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// ignore and don't store the colon&lt;/span&gt;
  &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;minutes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;minutesParser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//store minutes under the key 'minutes'&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time24hoursParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;00:24&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Right { hours:0, minutes: 24}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Excellent! Let's give this hours, minutes data object a type and call it a &lt;code&gt;TimeObj&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimeObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, let's take a breather now. Imagine you are an international &lt;a href="https://en.wikipedia.org/wiki/The_Amazing_Race" rel="noopener noreferrer"&gt;amazing race&lt;/a&gt; participant and you have just woken up on a bus after three consecutive connecting flights. The bus is currently traveling in a tunnel and you have no idea what year it is let alone the month, day or time. Spying a fellow passenger with a wristwatch, you groggily come to and have the following conversation:&lt;/p&gt;

&lt;p&gt;You: Hello fellow human. I appear to have regained consciousness after my intraplanetary travels. May I inquire  the reading on your portal time tracking device?&lt;br&gt;
Passenger: ooookay....&lt;br&gt;
Passenger: &amp;lt;looks down at watch&amp;gt;&lt;br&gt;
Passenger: uhhh, it is currently quarter past 1&lt;br&gt;
You: May I ascertain the position of the sun relative to our position as well?&lt;br&gt;
Passenger: huh? ohh&lt;br&gt;
Passenger: quarter past 1...pm&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzedq8equ96m719h96oqs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzedq8equ96m719h96oqs.png" alt="Alien asking for time pretending to be human" width="594" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So how do we parse the string "quarter past 1pm"? To do this, we will need to break down the structure of that string into a &lt;a href="https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form" rel="noopener noreferrer"&gt;grammar&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;long-form-time&amp;gt; ::= &amp;lt;segment&amp;gt; &amp;lt;relative&amp;gt; &amp;lt;hours12&amp;gt;&amp;lt;ampm&amp;gt;
&amp;lt;segment&amp;gt; ::= quarter | half
&amp;lt;relative&amp;gt; ::= past | to
&amp;lt;hours12&amp;gt; ::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
&amp;lt;ampm&amp;gt; ::= am | pm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Within our grammar, we allow sentences like "quarter past 1pm", "quarter to 5pm" and "half past 12pm".&lt;/p&gt;

&lt;p&gt;So let's get into it. The first thing to tackle would be the string "quarter" and "half".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;quarterParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quarter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;halfParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;half&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;segmentParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;either&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;quarterParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;halfParser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;segmentParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;half&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Right 30&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have a quarterParser to match on the string "quarter" and return back the number 15. We have a halfParser to match on the string "half" and return back the number 30. We then use the either combinator to try one and then the other if the first one fails.&lt;/p&gt;

&lt;p&gt;Next up will be tackling the &amp;lt;relative&amp;gt; segment of our grammar. This one requires a bit of thought. When we see the word "past" in the sentence "quarter past 1pm", what does it represent? &lt;/p&gt;

&lt;p&gt;It represents that the notion that we should add 15 minutes to whatever the hours component is. The type signature of this notion might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;TimeObj&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So let's get to it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minutesPast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours24&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;TimeObj&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;hours24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;minutes&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pastParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;past&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;minutesPast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break this down. First we define a function &lt;code&gt;minutesPast&lt;/code&gt; which takes in the minutes, then the hours in 24 hour format and returns back our 24 hour time object representation. &lt;br&gt;
Next we define the &lt;code&gt;pastParser&lt;/code&gt;, this parser matches on the string "past" and carries within it the minutesPast function.&lt;/p&gt;

&lt;p&gt;Similarly, we do the same for the &lt;code&gt;toParser&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minutesTo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours24&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;TimeObj&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours24&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;minutes&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;hours24&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;minutes&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;to&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;minutesTo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need a way to parse our &amp;lt;hours12&amp;gt; segment and convert that into a 24 hour format&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isValid12Hour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;num12Parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isValid12Hour&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;12 hour clock hours must be between 1 &amp;amp; 12&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;amParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;am&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours12&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours12&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;hours12&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pmParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours12&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours12&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;hours12&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;amPmParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;either&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;pmParser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hours12Parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;num12Parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;amPmParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours12&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours12Parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1am&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// Right 1&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours12Parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3pm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// Right 15&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours12Parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;14am&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// Left "12 hour clock hours must be between 1 &amp;amp; 12"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break this down. Using a similar technique to the &lt;code&gt;hours24Parser&lt;/code&gt; earlier in this article, we create the &lt;code&gt;num12Parer&lt;/code&gt; to only allow numbers between 1 &amp;amp; 12.&lt;br&gt;
The &lt;code&gt;amParser&lt;/code&gt; and &lt;code&gt;pmParser&lt;/code&gt; are Parsers that match on either am or pm and contains a function that converts 12 hour time to 24 hour time. We then join the &lt;code&gt;amParser&lt;/code&gt; and &lt;code&gt;pmParser&lt;/code&gt; together using the &lt;code&gt;either&lt;/code&gt; combinator.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;hours12Parser&lt;/code&gt; takes the &lt;code&gt;num12Parser&lt;/code&gt; and combines it using &lt;a href="https://gcanti.github.io/parser-ts/modules/Parser.ts.html#seq" rel="noopener noreferrer"&gt;seq&lt;/a&gt; which is a combinator that passes results from the first Parser to the next Parser if it succeeds. If it succeeds, we pass the parsed hours12 number to the &lt;code&gt;amPmParser&lt;/code&gt;, as that contains a function inside, we use &lt;code&gt;P.map&lt;/code&gt; to apply our hours12 number to the contained function getting back a number representing the hours in 24 hour time.&lt;/p&gt;

&lt;p&gt;Phew! We now have all the parsers for our individual segments. Time to glue them altogether.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;longFormParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;segmentParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// [1]&lt;/span&gt;
  &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chainFirst&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spaces1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// [2]&lt;/span&gt;
  &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;either&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;pastParser&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// [3]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chainFirst&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spaces1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;//ignore 1 or more spaces&lt;/span&gt;
  &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;hours12Parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// [4]&lt;/span&gt;
      &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;hours12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours12&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// [5]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;longFormParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quarter to 12am&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;//Right {hours:23, minutes:45}&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;longFormParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;half past 12am&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;//Right {hours:0, minutes: 30}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's talk it out. [1] We start with our &lt;code&gt;segmentParser&lt;/code&gt; to match on "quarter" or "half" and get back the number 15 or 30. [2] We then use &lt;code&gt;chainFirst&lt;/code&gt; with &lt;code&gt;S.spaces1&lt;/code&gt; to ignore 1 or more whitespace characters. [3] We then use either our &lt;code&gt;toParser&lt;/code&gt; or &lt;code&gt;pastParser&lt;/code&gt; to get our function of the shape &lt;code&gt;minutes -&amp;gt; hours -&amp;gt; TimeObj&lt;/code&gt;. Since we have our minutes already, we partially apply the minutes to our function [3]. After ignoring some more spaces, we use the &lt;code&gt;hours12Parser&lt;/code&gt; to extract out the number of hours in 24 hour time [4]. Finally, we have the last argument for our function from [3] and we have the time represented in our &lt;code&gt;TimeObj&lt;/code&gt; format.&lt;/p&gt;

&lt;p&gt;With that, our alien friend now knows what time it is to help it win the amazing race!&lt;/p&gt;

&lt;p&gt;To conclude, I leave you with a poem&lt;/p&gt;

&lt;p&gt;A string is not only a string&lt;br&gt;
Wherewith a data structure lies within&lt;br&gt;
Regex don't you use&lt;br&gt;
Use Parser combinators for the win!&lt;br&gt;
~derp&lt;/p&gt;

&lt;p&gt;Link to codesandbox:&lt;br&gt;
&lt;a href="https://codesandbox.io/s/time-parser-example-jwrwk3?file=/src/index.ts" rel="noopener noreferrer"&gt;https://codesandbox.io/s/time-parser-example-jwrwk3?file=/src/index.ts&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>Advanced parser combinators with parser-ts</title>
      <dc:creator>Derp</dc:creator>
      <pubDate>Mon, 12 Dec 2022 04:08:00 +0000</pubDate>
      <link>https://dev.to/derp/parser-ts-4dad</link>
      <guid>https://dev.to/derp/parser-ts-4dad</guid>
      <description>&lt;p&gt;In the last part, we used the power of parser combinators to systematically parse strings into dates. However a Parser is unbound in its return type and you can make it returning &lt;em&gt;anything&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Today we will be using this ability and combining it with the state monad to draw things on a canvas in clean, modular way.&lt;/p&gt;

&lt;p&gt;The problem we will be tackling today will be the turtle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bNC-p1GD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jnud3j2ypfmh6sv6szin.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bNC-p1GD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jnud3j2ypfmh6sv6szin.jpg" alt="Image description" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No not that turtle, this one:&lt;br&gt;
&lt;a href="https://docs.python.org/3/library/turtle.html"&gt;https://docs.python.org/3/library/turtle.html&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rDTji_kW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/moakp9nido1omcorwewf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rDTji_kW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/moakp9nido1omcorwewf.png" alt="Image description" width="250" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Python turtles are great, you can give them a list of instructions and these turtles will dutifully execute them to create fine art. As our turtle program will be simpler, we will give our turtle a short name. Meet Bob.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UsI-7sDg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vbnp1r9j2so6ratp3k1a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UsI-7sDg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vbnp1r9j2so6ratp3k1a.png" alt="Image description" width="128" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For simplicity, Bob will only understand a small subset of commands that python turtles can understand. Bob understands the following strings: forward X, left X, right X, penUp and penDown. These commands will respectively move, rotate and give Bob the ability to draw straight lines on a canvas.&lt;/p&gt;

&lt;p&gt;To tackle this problem, we will be splitting it up into three parts&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teaching Bob how to understands strings&lt;/li&gt;
&lt;li&gt;Teaching Bob how to store state&lt;/li&gt;
&lt;li&gt;Teach Bob how to draw on the page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once we have tackled these three sub problems, we will join them altogether and have our program. &lt;/p&gt;
&lt;h2&gt;
  
  
  Teaching Bob to understand strings
&lt;/h2&gt;

&lt;p&gt;The first problem we will tackle is to teach Bob to understand strings. Building on the &lt;a href="https://dev.to/derp/parser-combinators-in-typescript-with-parser-ts-part-1-46o3"&gt;last article&lt;/a&gt;, we will use parser combinators. Let's   teach Bob how to understand "forward 10".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const forwardStrParser: P.Parser&amp;lt;string, number&amp;gt; = pipe(
  S.string("forward"),
  P.chain(() =&amp;gt; S.spaces1),
  P.chain(() =&amp;gt; S.int)
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break this down. First (1) we match on the string "forward" with &lt;code&gt;S.string("forward")&lt;/code&gt;, we then match on one or more spaces with &lt;code&gt;P.chain(() =&amp;gt; S.spaces1))&lt;/code&gt; and finally we have &lt;code&gt;P.chain(() =&amp;gt; S.int)&lt;/code&gt;. Note that we are ignoring the input from the string "forward" and the spaces and we only keep the number at the end.&lt;/p&gt;

&lt;p&gt;In the end, we have a Parser that takes in a string and returns back a number. However as Parsers are functors, they have a method &lt;code&gt;map&lt;/code&gt; which allows us to transform that number into any other type. We will get back to this point later in the article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Teaching Bob to store state
&lt;/h2&gt;

&lt;p&gt;Bob needs to know where he is on the canvas, which direction he is facing and whether or not he is currently drawing or not. Let's create a minimal representation of this state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const INITIAL = {
  dir: 0, // direction our turtle is facing in degrees
  pos: [0, 0], // our initial x,y position
  isDrawing: false // our way of putting the 'pen' up or down.
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the initial state above, we will need some sort of mechanism to transform that state and extract some sort of output from the new state. Thankfully, we can use the &lt;a href="https://dev.to/derp/state-monad-in-fp-ts-5c79"&gt;state monad&lt;/a&gt; to give this to us. &lt;/p&gt;

&lt;p&gt;To summarise, the state monad has a type signature of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;State s a :: s -&amp;gt; (a,s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this says is that all our state monads are state transition functions that take in some initial state and returns back a pair of some output &lt;code&gt;a&lt;/code&gt; and some new state s.&lt;/p&gt;

&lt;p&gt;Let's ignore the output for now and see how we might write the state transition function to move Bob forward &lt;code&gt;n&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const forward = (n: number): St.State&amp;lt;State, ?&amp;gt; =&amp;gt; (
  state: State
) =&amp;gt; {
  const [x, y] = state.pos; // 1
  const dirRadians = degToRad(state.dir);
  const xComponent = Math.cos(dirRadians);
  const yComponent = Math.sin(dirRadians);

  const newState = { //2
    isDrawing: state.isDrawing,
    dir: state.dir,
    pos: [x + n * xComponent, y + n * yComponent]
  };
  return [?, newState]; // 3
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break this down. This is a function that takes in a number &lt;code&gt;n&lt;/code&gt; spaces to move forward and returns back the state monad &lt;code&gt;St.State&amp;lt;State,?&amp;gt;&lt;/code&gt;. Now state monads are functions that take in an initial state and return back some output and a new state.&lt;/p&gt;

&lt;p&gt;In section 1, we are destructuring the x &amp;amp; y co-ordinate from the current position. We then do some trigonometry to calculate the x &amp;amp; y component based on the current direction of our turtle. Once we have all that, we start constructing our new state in section 2. As moving forward does not change the isDrawing or direction of our turtle, we pass those unchanged from our initial state. Our new co-ordinates are calculated by multiplying the n spaces that we are moving forward by the x &amp;amp; y components. Finally in section 3, we return back our pair of some output (?) and our new state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Teaching Bob to draw on the page
&lt;/h2&gt;

&lt;p&gt;In our example, we are using a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API"&gt;canvas API&lt;/a&gt; to draw on the page. However, one important detail is that we don't want to immediately draw on the page, but instead create a function that will only draw on the page &lt;em&gt;when executed&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;To do this, we define a &lt;code&gt;DrawFunction&lt;/code&gt; which has the type signature of&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type DrawFunction = (context: CanvasRenderingContext2D) =&amp;gt; void;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is, this is a function that takes in the context as an argument so that when executed, we can perform side effects like &lt;code&gt;context.stroke()&lt;/code&gt; drawing our lines on the canvas.&lt;/p&gt;

&lt;p&gt;For example, our lineTo function will look like the below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const lineTo = (x: number, y: number): DrawFunction =&amp;gt; (ctx) =&amp;gt; {
  ctx.lineTo(x, y);
  ctx.stroke();
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break this down. We have a &lt;code&gt;lineTo&lt;/code&gt; function that takes in the new x &amp;amp; y co-ordinate that we should move to from our previous x&amp;amp;Y co-ordinate stored in the internal canvas state. We then call &lt;code&gt;lineTo&lt;/code&gt; which adds a new line to the current sub-path inside the canvas state. As this does not actually fill in the line, we will then need to call &lt;code&gt;stroke&lt;/code&gt; to fill in the line causing the line to appear on the screen. As &lt;code&gt;lineTo&lt;/code&gt; is a higher order function, the lines won't be drawn until both the &lt;code&gt;(x,y)&lt;/code&gt; and &lt;code&gt;(ctx)&lt;/code&gt; arguments are supplied.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bringing it all together
&lt;/h2&gt;

&lt;p&gt;In the previous section, we saw how to parse a string, transform state and draw onto a canvas individually. In this section, we will connect them all with the power of functional programming.&lt;/p&gt;

&lt;p&gt;First, from our forward string parser, we ended up with a parser from strings to numbers. &lt;code&gt;forwardStrParser : P.Parser&amp;lt;string, number&amp;gt;&lt;/code&gt;, however as alluded to earlier, Parsers a functors and we can map that number and pass it to our forward function that returns a state monad to get a parser that takes in a string and returns back a state transition.&lt;/p&gt;

&lt;p&gt;Ie&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// forwardStrParser :: P.Parser&amp;lt;string, number&amp;gt;
const forwardParser = pipe(forwardStrParser, P.map(forward));
// forward Parser :: P.Parser&amp;lt;string, S.State&amp;lt;State, ?&amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have a parser that takes in a string and returns back state transition function.&lt;/p&gt;

&lt;p&gt;From the state transition function, we glossed over the output of each step. What we can do is to return a DrawFunction for each step so as we go through our state transitions, we can build a corresponding DrawFunction. &lt;/p&gt;

&lt;p&gt;Ie&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const forward = (n: number): St.State&amp;lt;State, DrawFunction&amp;gt; =&amp;gt; (
  state: State
) =&amp;gt; {
  // discussed in section 2
  const [x, y] = state.pos;
  const dirRadians = degToRad(state.dir);
  const xComponent = Math.cos(dirRadians);
  const yComponent = Math.sin(dirRadians);

  const newState = {
    isDrawing: state.isDrawing,
    dir: state.dir,
    pos: [x + n * xComponent, y + n * yComponent]
  };

  // **New** Look here below:
  const drawFunction: DrawFunction = state.isDrawing
    ? lineTo(newState.pos[0], newState.pos[1])
    : moveTo(newState.pos[0], newState.pos[1]);

  return [drawFunction, newState];
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break this down. Here we choose between two DrawFunctions depending on our current state. If &lt;code&gt;isDrawing&lt;/code&gt; is true, we will choose the &lt;code&gt;lineTo&lt;/code&gt; DrawFunction whereas if it is not, we will choose the &lt;code&gt;moveTo&lt;/code&gt; DrawFunction. The moveTo function has not been shown above but can be seen in the codesandbox at the end. &lt;/p&gt;

&lt;p&gt;Hence our forwardParser has the final type of &lt;code&gt;P.Parser&amp;lt;string, S.State&amp;lt;State, DrawFunction&amp;gt;&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seeing it in action
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--srqklXjW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/grjy63i0b8mg847e4wug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--srqklXjW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/grjy63i0b8mg847e4wug.png" alt="A single horizontal black line" width="507" height="507"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { pipe } from "fp-ts/function";
import { run } from "parser-ts/lib/code-frame";
import * as E from "fp-ts/lib/Either";

const initialState: State = {
  isDrawing: true,
  dir: 0,
  pos: [0, 0]
}; // 1

const c = &amp;lt;HTMLCanvasElement&amp;gt;document.getElementById("myCanvas");
let ctx = c.getContext("2d");
if (ctx == null) throw new Error("canvas not found"); 
ctx.lineWidth = 5;
ctx.moveTo(initialState.pos[0], initialState.pos[1]); // 2

const eitherState = run(forwardParser, "forward 100"); // 3
pipe(
  eitherState,
  E.fold(console.error, (state) =&amp;gt; { // 4
    const [drawFn, _newState] = state(initialState); // 5
    drawFn(ctx); // 6
  })
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break this down. In (1), we set the initial state of Bob. Note that we are setting isDrawing to be true right off the bat as we want to draw a line instead of just moving Bob.&lt;/p&gt;

&lt;p&gt;In (2), we need to get our reference in JS to our HTML canvas element. We then update the context to match our initial state.&lt;/p&gt;

&lt;p&gt;In 3, we run the forward parser with our string &lt;code&gt;"forward 100"&lt;/code&gt;. This returns back either an error message if our string fails to parse or our state transition. If it is an error message, we log the error to the console, however if is our state monad (4), we run the state against the initial state in (5) to get a drawFunction and the updated state. As we are only interested in the drawFunction, we ignore the updated state and we execute the drawFunction by providing the last context argument in (6) causing our line to appear on the screen. &lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding many commands
&lt;/h2&gt;

&lt;p&gt;Currently Bob only understands how to draw lines forwards. We won't cover all the commands here however they all follow a similar pattern in that we create a Parser for every command that we want Bob to understand.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forwardParser :: P.Parser&amp;lt;State, DrawFunction&amp;gt;
leftParser :: P.Parser&amp;lt;State, DrawFunction&amp;gt;
rightParser :: P.Parser&amp;lt;State, DrawFunction&amp;gt;
penUpParser :: P.Parser&amp;lt;State, DrawFunction&amp;gt;
penDownParser :: P.Parser&amp;lt;State, DrawFunction&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have our parsers, we can join them together with &lt;a href="https://gcanti.github.io/parser-ts/modules/Parser.ts.html#alt"&gt;alt&lt;/a&gt; to create our overall turtleParser&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const turtleParser = pipe(
  forwardParser,
  P.alt(() =&amp;gt; leftParser),
  P.alt(() =&amp;gt; rightParser),
  P.alt(() =&amp;gt; penUpParser),
  P.alt(() =&amp;gt; penDownParser)
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, this is still a parser that takes in a single string and returns back a single state transition. Ie&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;turtleParser :: P.Parser&amp;lt;State, DrawFunction&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we have many strings in an array, what we can do is run the turtleParser on every string in the array to get back an array of &lt;code&gt;Either&amp;lt;string,St.State&amp;lt;State, DrawFunction&amp;gt;&lt;/code&gt; and use &lt;a href="https://gcanti.github.io/fp-ts/modules/Either.ts.html#sequencearray"&gt;sequenceArray&lt;/a&gt; to convert that into an Either[]&amp;gt;.&lt;/p&gt;

&lt;p&gt;Let's see that in action&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const cmds: string[]= [
  "forward 100",
  "right 90",
  // ...other commands not shown
]; // 1

const parsed = cmds.map((cmd) =&amp;gt; run(turtleParser, cmd)) // 2
// E.sequenceArray :: &amp;lt;E, A&amp;gt;(as: readonly Either&amp;lt;E, A&amp;gt;[]) =&amp;gt; Either&amp;lt;E, readonly A[]&amp;gt; // 3
const maybeTransitions = E.sequenceArray(parsed); // 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break that down. In (1), we have our array of strings which we then map into an array of Parsers in (2). Now parsed has the type of &lt;code&gt;parsed:: E.Either&amp;lt;string, St.State&amp;lt;State,DrawFunction&amp;gt;&amp;gt;[]&lt;/code&gt; however note that we have ended up with an array of Eithers which if we would then manually need to check on whether it was a Left or a Right and then only if it was a Right, would we want to progress. As this is a common task in functional programming, we reach for the utility function sequenceArray(3) which takes in an array of Eithers and runs through them sequentially and checks whether each element is a Left or a Right. If any element is Left, it will return back that result, however if all the elements in the array are Right, then it will collect them all into a single Array. In (4), we call this function on our array &lt;code&gt;parsed&lt;/code&gt; to get back our &lt;code&gt;maybeTransitions&lt;/code&gt; which is either an error or an array of State transitions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (E.isRight(maybeTransitions)) {
  const transitions = maybeTransitions.right;
  const [drawFns, finalState] = St.sequenceArray(transitions)(INITIAL); // 5

  drawFns.forEach((drawFn) =&amp;gt; drawFn(ctx as CanvasRenderingContext2D)); //6
  drawTurtle(finalState.pos[0], finalState.pos[1], finalState.dir)(ctx); // 7
} else {
  console.error(maybeTransitions.left);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have our array of state transitions in (5), we then call the State monad's version of sequenceArray to get back an array of drawFunctions and our final state. We then pass the final argument in all of our drawFunctions in (6) drawing our changes to the canvas. In (7), we draw Bob on our canvas with his position and direction based of our final state at the end of all our state transitions.&lt;/p&gt;

&lt;p&gt;In conclusion, we have ended up with a program which neatly separates the concerns of parsing, state and side effects and joined them all with the power of functional programming. If you would like to have a play yourself, please feel free to check out the codesandbox link below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/parser-combinator-example-cjuh40"&gt;https://codesandbox.io/s/parser-combinator-example-cjuh40&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>functional</category>
    </item>
    <item>
      <title>Abstracting away async with fp-ts</title>
      <dc:creator>Derp</dc:creator>
      <pubDate>Tue, 22 Nov 2022 12:32:31 +0000</pubDate>
      <link>https://dev.to/derp/abstracting-away-async-with-fp-ts-ig</link>
      <guid>https://dev.to/derp/abstracting-away-async-with-fp-ts-ig</guid>
      <description>&lt;p&gt;&lt;strong&gt;Business logic is usually quite simple. It is the plumbing that is hard. You can use ap to isolate your business logic from your plumbing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider the e-commerce store Widgi-tech:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmatxb8ho4y3tc7w3jyt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmatxb8ho4y3tc7w3jyt.png" alt="Widgets for $3 each, buying 3 plus shipping"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The business logic for calculating the price of an order is usually quite simple. In the above example, our widgets are being sold for $3 each, we are buying three of them and we add shipping on top of that. The complexity usually comes from mixing our business logic with concerns like error handling and asynchronicity.&lt;/p&gt;

&lt;p&gt;To begin, lets write our getTotal function.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 typescript
const getTotal = (price:number) =&amp;gt; (qty:number) =&amp;gt; (shipping:number) =&amp;gt; price * qty + shipping;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Job done right? Well no, at Widgi-tech, each one of those arguments is the responsibility of a different team. The pricing team sets prices today based on the prices based on how many of an item you order. Oh and sometimes prices aren't available for a given SKU yet. Qty is controlled by the inventory team which tracks how many widgets they have in their warehouse and you can't order more of a widget than they have and shipping costs depend on the location and total weight of the order. Oh and you can't send items to addresses outside their delivery zone.&lt;/p&gt;

&lt;p&gt;The problem then starts to look a bit more like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fp-ts/Either&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;SKU&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;getPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;SKU&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Either&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;//just ignore that we are representing money with a number type for now&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;getQty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;SKU&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Either&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;getShipping&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;SKU&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;E&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Either&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let's break this down.&lt;/p&gt;

&lt;p&gt;We have a function signature for &lt;code&gt;getPrice&lt;/code&gt; that takes in the SKU and the qty of an item and returns back either an error message (string) or the per unit price of the item (number).&lt;/p&gt;

&lt;p&gt;We have a function signature for &lt;code&gt;getQty&lt;/code&gt; that takes in the SKU and the quantity of items and returns back either an error message when they can't fulfill the item or just the quantity back.&lt;/p&gt;

&lt;p&gt;We have a function signature for &lt;code&gt;getShipping&lt;/code&gt; that takes in the SKU, the quantity of items and the address. We either get back an error message when they can't send the items there or we get back the shipping cost.&lt;/p&gt;

&lt;p&gt;Now we are at a conundrum, we started with our beautiful and simple &lt;code&gt;getTotal&lt;/code&gt; function but now we have to care about error messages and the ugliness of error messages and reality. How do we make the &lt;code&gt;getTotal&lt;/code&gt; function fit?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F387w25hjrsr948rkwq4i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F387w25hjrsr948rkwq4i.png" alt="Square peg, round hole"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The secret is that Either is an instance of an applicative functor. We can lift our simple &lt;code&gt;getTotal&lt;/code&gt; function into an Either and then apply each of our arguments sequentially.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 typescript
/** We lift getTotal into E.Either and apply each argument sequentially */
const price: E.Either&amp;lt;string, number&amp;gt; = pipe(
  E.of(getTotal),
  E.ap(getPrice(sku, qty)),
  E.ap(getQty(sku, qty)),
  E.ap(getShipping(sku, qty, address))
);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/practical-lewin-yqsthc?file=/src/index.ts" rel="noopener noreferrer"&gt;https://codesandbox.io/s/practical-lewin-yqsthc?file=/src/index.ts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's take a closer look at how ap works by examining the type signature of different parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;E.of(getTotal)&lt;/code&gt; This lifts our getTotal function into an Either and the type signature of this is &lt;code&gt;E.Either&amp;lt;never, (price: number) =&amp;gt; (qty: number) =&amp;gt; (shipping: number) =&amp;gt; number&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getPrice(sku, qty)&lt;/code&gt; This is an &lt;code&gt;E.Either&amp;lt;string, number&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;E.ap&lt;/code&gt; This is the Either ap function, in this case, it has a signature of &lt;code&gt;&amp;lt;string, number&amp;gt;(fa: E.Either&amp;lt;string, number&amp;gt;) =&amp;gt; &amp;lt;B&amp;gt;(fab: E.Either&amp;lt;string, (a: number) =&amp;gt; B&amp;gt;) =&amp;gt; E.Either&amp;lt;string, B&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pipe(E.of(getTotal), E.ap(getPrice(sku,qty))&lt;/code&gt; This has a type signature of &lt;code&gt;E.Either&amp;lt;string, (qty: number) =&amp;gt; (shipping: number) =&amp;gt; number&amp;gt;&lt;/code&gt; Notice the difference in this signature to the one of &lt;code&gt;E.of(getTotal)&lt;/code&gt;. &lt;strong&gt;We have partially applied our price in our getTotal function&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Phew. That was a lot but let's take a step back and admire what we have just done. By using the power of applicative, we have isolated the business logic inside our getTotal function and deferred all the error handling to our &lt;code&gt;Either&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;So why is this isolation useful? Because business logic changes all the time. Let's say there's a promotion where orders get free shipping if the total order is over $100, what that look like?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 typescript
const getTotal = (price:number) =&amp;gt; (qty:number) =&amp;gt; (shipping:number) =&amp;gt; {
  const exShipping = price * qty;
  const shippingFee = exShipping &amp;lt; 100 ? shipping : 0;
  return exShipping + shippingFee;
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Notice the lack of any change to the plumbing code or any of the wiring. Think also about how easy it is to test this function in isolation.&lt;/p&gt;

&lt;p&gt;Now at this point, you the reader will probably be thinking. Hang on Derp, our different departments would have APIs that are asynchronous. How do we handle that?&lt;/p&gt;

&lt;p&gt;To answer that question, we'll need to reach for another applicative. &lt;code&gt;Either&lt;/code&gt;s encapsulate the concept of an error state, a &lt;code&gt;Task&lt;/code&gt; encapsulates the concept of asynchronicity. The applicative we need is a &lt;code&gt;TaskEither&lt;/code&gt; which encapsulates both.&lt;/p&gt;

&lt;p&gt;So our changes are:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="cm"&gt;/** Note: all that chnages is going from E.Either to TE.TaskEither */&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SKU&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;TE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TaskEither&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetQty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SKU&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;TE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TaskEither&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetShipping&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SKU&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;TE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TaskEither&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="cm"&gt;/** We lift getTotal into TE.TaskEither and apply each argument sequentially */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TaskEither&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;TE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getTotal&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;TE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="nx"&gt;TE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getQty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="nx"&gt;TE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getShipping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;TE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;totalP&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`total is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Notice our simple, beautiful &lt;code&gt;getTotal&lt;/code&gt; function has remained completely unchanged. It cares not for the messy, asynchronous and error prone state of the world. We have successfully abstracted all of this away from it with the power of fp-ts and functional programming.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/dreamy-hofstadter-4vuzou?file=/src/index.ts" rel="noopener noreferrer"&gt;https://codesandbox.io/s/dreamy-hofstadter-4vuzou?file=/src/index.ts&lt;/a&gt;&lt;/p&gt;

</description>
      <category>functional</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Promisifying CSS animation with timeout fallback</title>
      <dc:creator>Derp</dc:creator>
      <pubDate>Thu, 10 Mar 2022 01:15:46 +0000</pubDate>
      <link>https://dev.to/derp/promisifying-css-animation-with-timeout-fallback-28ml</link>
      <guid>https://dev.to/derp/promisifying-css-animation-with-timeout-fallback-28ml</guid>
      <description>&lt;p&gt;So I came across this interesting problem dealing with state updates and animations. I wanted to create a utility function that would execute a state update after an animation had finished but with a timeout fallback in case a developer forgot to animate the element.&lt;/p&gt;

&lt;p&gt;This is useful for React applications where you want to wait for a slide-out animation for your popup to complete before updating your state, causing your popup to be removed from the DOM.&lt;/p&gt;

&lt;p&gt;Let's start with the first two problems&lt;br&gt;
1) We need an event listener to listen for the CSS tranistionend event that is fired from the animated element. When it is triggered, call some function &lt;code&gt;fn&lt;/code&gt;.&lt;br&gt;
2) We need a timeout function as a fallback. When the timeout triggers, call some function &lt;code&gt;fn&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addTransitionEndListener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;transitionend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addTimeOut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we want to promisify these two functions inside &lt;code&gt;Promise.race&lt;/code&gt; and apply our state update when either one of these two promises is settled. We will also add some convenience types.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CallbackFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;promisify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CallbackFn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addTransitionEndListenerP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;promisify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;addTransitionEndListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addTimeOutP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;promisify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;addTimeOut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someDuration&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// 4&lt;/span&gt;
&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;race&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;addTransitionEndListenerP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;addTimeOutP&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;state update goes here&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a lot to digest here so let's go through it section by section.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;Effect&lt;/code&gt; represents a function with no return value. &lt;code&gt;CallbackFn&lt;/code&gt; expects an &lt;code&gt;Effect&lt;/code&gt; function as an argument and does not return anything. Both &lt;code&gt;addTransitionEndListener&lt;/code&gt; and &lt;code&gt;addTimeOut&lt;/code&gt; are of type &lt;code&gt;CallbackFn&lt;/code&gt; after the first argument.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;promisify&lt;/code&gt; function expects a &lt;code&gt;CallbackFn&lt;/code&gt; and returns a Promise. We are passing in &lt;code&gt;resolve(null)&lt;/code&gt; as the &lt;code&gt;Effect&lt;/code&gt; fn as we do not care about returning anything from our Promise for now.&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;promisify&lt;/code&gt;, we turn &lt;code&gt;addTransitionEndListener&lt;/code&gt; and &lt;code&gt;addTimeOut&lt;/code&gt; into something that returns a Promise.&lt;/li&gt;
&lt;li&gt;We use &lt;code&gt;Promise.race&lt;/code&gt; and &lt;code&gt;finally&lt;/code&gt; to perform our mock state update regardless of whether the &lt;code&gt;transitionend&lt;/code&gt; event first first or &lt;code&gt;someDuration&lt;/code&gt; passes first. &lt;code&gt;someDuration&lt;/code&gt; and &lt;code&gt;someElement&lt;/code&gt; are defined outside of here.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After wiring all this up, we now have another problem. How do we remove the event listener or clear the timeout once either event happens? Keep in mind that &lt;code&gt;removeEventListener&lt;/code&gt;requires a reference to the same function that was passed in to &lt;code&gt;addEventListener&lt;/code&gt; and &lt;code&gt;clearTimeout&lt;/code&gt;requires the interval id which is only returned when &lt;code&gt;setTimeout&lt;/code&gt; is called.&lt;/p&gt;

&lt;p&gt;To solve this, let's change the type of &lt;code&gt;CallbackFn&lt;/code&gt; to return a &lt;code&gt;CleanupFn&lt;/code&gt; which is a type alias for &lt;code&gt;Effect&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CleanupFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CallbackFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;CleanupFn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we will need to change &lt;code&gt;addTransitionEndListener&lt;/code&gt; and &lt;code&gt;addTimeOut&lt;/code&gt; to return a CleanupFn.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addTransitionEndListener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;CleanupFn&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;transitionend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;transitionend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addTimeOut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;CleanupFn&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeoutID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutID&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will also need to change promisify to return a pair of a Promise and a Cleanup function. We will then need to provide another function that wraps &lt;code&gt;Promise.race&lt;/code&gt; so that it calls all the cleanup functions in the finally block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PromiseCleanup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CleanupFn&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;promisify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CallbackFn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;cleanupFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cleanupFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="nx"&gt;cleanupFn&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;promisifyRace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;promiseCleanups&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PromiseCleanup&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;promises&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;promiseCleanups&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cleanups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;promiseCleanups&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([,&lt;/span&gt; &lt;span class="nx"&gt;cleanup&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cleanup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;race&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;promises&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cleanups&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cleanup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cleanup&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are free to use it like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt; &lt;span class="nx"&gt;promisifyRace&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;transitionP&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;durationP&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stateUpdate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Github link: &lt;a href="https://github.com/wibily/promisifyCleanup"&gt;https://github.com/wibily/promisifyCleanup&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Codesandbox link:&lt;br&gt;
&lt;a href="https://codesandbox.io/s/animationend-fiddle-o2scuh?file=/src/index.ts"&gt;https://codesandbox.io/s/animationend-fiddle-o2scuh?file=/src/index.ts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: codesandbox link builds on top of the idea above by passing in both the resolve, reject Promise executor to the promisify function allowing the caller to choose whether they want to resolve or reject the Promise.&lt;/p&gt;

&lt;h3&gt;
  
  
  TLDR;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Convert your asynchronous side-effect functions to return a pair of a Promise and a cleanup function&lt;/li&gt;
&lt;li&gt;As we don't have Promise.cancel, create your own Promise.race/any/all implementation that runs all the cleanup functions in the finally block &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Aside:&lt;br&gt;
TIL that there is a difference between animationend and transitionend. &lt;a href="https://stackoverflow.com/a/41530600/6036932"&gt;Thank you Jessica&lt;/a&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>javascript</category>
    </item>
    <item>
      <title>State monad in fp-ts</title>
      <dc:creator>Derp</dc:creator>
      <pubDate>Wed, 19 Jan 2022 12:52:46 +0000</pubDate>
      <link>https://dev.to/derp/state-monad-in-fp-ts-5c79</link>
      <guid>https://dev.to/derp/state-monad-in-fp-ts-5c79</guid>
      <description>&lt;p&gt;Consider the gumball machine&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnrmk6ps212klbxbyrylj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnrmk6ps212klbxbyrylj.png" alt="Picture of a gumball machine"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is in a unpaid or paid state and the output of it is either nothing or a gumball.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Unpaid&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Paid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Gumball&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Gumball&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;O&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Gumball&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's consider the transitions. When we pay 50c into this gumball machine, it will put it into the Paid state. If the machine is in a paid state and we turn the handle, we get a gumball and the machine reverts back to an Unpaid state. All other transitions, we get nothing and the state remains the same.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpdv7mkwcaa1d2sl5a2vq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpdv7mkwcaa1d2sl5a2vq.png" alt="State transition diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To model these state transitions, let's use the &lt;a href="https://gcanti.github.io/fp-ts/modules/State.ts.html#state-interface" rel="noopener noreferrer"&gt;fp-ts State type&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// State s a :: s -&amp;gt; (a,s)&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which translated means give me an initial state s and I'll give you some output A and the new state. Now calling this interface State is a bit confusing as it is really more of a State processor whereas the actual state type is inside the generic parameter S.&lt;/p&gt;

&lt;p&gt;Hence our pay and turn function looks like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//state transition functions are of the type State -&amp;gt; (Output, State)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Output&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;O&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;none&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Paid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;O&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;none&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Output&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unpaid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;O&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;none&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Paid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;O&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Gumball&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unpaid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;//Single usage:&lt;/span&gt;
&lt;span class="nf"&gt;pay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unpaid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// [O.none, "Paid"];&lt;/span&gt;
&lt;span class="nf"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Paid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// [O.some("Gumball"), "Unpaid"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now here comes the tricky part, how do we combine these functions together to build up our state machine? The key is that State s is an instance of Monad and that we can use bind/chain to combine our different state transition functions into a single one. Switching to Haskell for a second,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// (&amp;gt;&amp;gt;=) :: (Monad m) =&amp;gt; m a -&amp;gt; (a -&amp;gt; m b) -&amp;gt; m b
// instance Monad (State s)
// (&amp;gt;&amp;gt;=) :: (Monad (State s)) =&amp;gt; State s a -&amp;gt; (a -&amp;gt; State s b) -&amp;gt; State s b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's unpack this. First we have the definition of bind (&amp;gt;&amp;gt;=) or chain as it is in known in fp-ts. Next we see that our instance of Monad is (State s) so we should substitute (State s) wherever we see m. Finally we are left with the definition of bind specialised to the State monad. which we will take a look at now in parts. Ie &lt;code&gt;State s a&lt;/code&gt;, &lt;code&gt;(a -&amp;gt; State s b)&lt;/code&gt; and &lt;code&gt;State s b&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//State s a :: s -&amp;gt; (a,s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We remember that &lt;code&gt;State s a&lt;/code&gt; is a state transition function that takes a state s and returns back an output a and a new state. So we expand it out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//a - &amp;gt; State s b :: a -&amp;gt; s -&amp;gt; (b, s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expanding out &lt;code&gt;State s b&lt;/code&gt; to &lt;code&gt;s -&amp;gt; (b,s)&lt;/code&gt;, we see that the second part is a function that takes in some input of type &lt;code&gt;a&lt;/code&gt;, some state of type &lt;code&gt;s&lt;/code&gt; and returns back a new output of type &lt;code&gt;b&lt;/code&gt; and a new state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//State s b :: s -&amp;gt; (b, s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The return value is a new state transition function of &lt;code&gt;State s b&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// (&amp;gt;&amp;gt;=) :: (State s) =&amp;gt; State s a -&amp;gt; (a -&amp;gt; State s b) -&amp;gt; State s b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's bring it altogether now. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Bind takes the first state transition function and gets the output and state from that to feed it to the second state transition function creating a new combined state transition function.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Switching back to fp-ts land and our gumball machine, how would we combine our &lt;code&gt;pay(50)&lt;/code&gt; and &lt;code&gt;turn&lt;/code&gt; functions? Keeping in mind that &lt;code&gt;S.chain&lt;/code&gt; is a flipped version of bind, we use the following: Note that we use &lt;code&gt;() =&amp;gt; turn&lt;/code&gt; because our gumball machine transitions do not depend on the output of a previous state transition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;combined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nf"&gt;pay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nf"&gt;combined&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unpaid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// [O.some("Gumball"), "Unpaid"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we know that monadic composition is available to us, we can use functions like &lt;code&gt;S.sequeunceArray&lt;/code&gt; to combine an array of state transition functions into a single state transition function that returns a collected array of outputs as well as the final state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;pay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;pay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;pay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;finalState&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sequenceArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unpaid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numGumballs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;O&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isSome&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sample code: &lt;a href="https://codesandbox.io/s/ancient-firefly-3lgrg?file=/src/index.ts" rel="noopener noreferrer"&gt;https://codesandbox.io/s/ancient-firefly-3lgrg?file=/src/index.ts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Further reading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://brandon.si/code/the-state-monad-a-tutorial-for-the-confused/" rel="noopener noreferrer"&gt;http://brandon.si/code/the-state-monad-a-tutorial-for-the-confused/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikibooks.org/wiki/Haskell/Understanding_monads/State" rel="noopener noreferrer"&gt;https://en.wikibooks.org/wiki/Haskell/Understanding_monads/State&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>functional</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Advent of code - day 6</title>
      <dc:creator>Derp</dc:creator>
      <pubDate>Sat, 08 Jan 2022 06:47:41 +0000</pubDate>
      <link>https://dev.to/derp/advent-of-code-day-6-mab</link>
      <guid>https://dev.to/derp/advent-of-code-day-6-mab</guid>
      <description>&lt;p&gt;This challenge is to create a state machine and find the end state after n iterations.&lt;/p&gt;

&lt;p&gt;This seems like a perfect opportunity to dig deeper with the State Monad which i have been struggling with for a while. First, the interface which is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// newtype State s a = State { runState :: s -&amp;gt; (a, s) }
interface State&amp;lt;S, A&amp;gt; {
  (s: S): [A, S]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A more accurate name for this would be State processor. The type S represents the state whereas the A represents some sort of interesting output from the State processor.&lt;/p&gt;

&lt;p&gt;First, I create my nextFishState function which has the signature:&lt;br&gt;
&lt;code&gt;nextFishState :: number -&amp;gt; [number]&lt;/code&gt;. Now in my nextState function which has the singature: &lt;code&gt;nextState: S.State&amp;lt;number[], number&amp;gt;&lt;/code&gt;, I use chain to apply the nextFishState function to every element in my number[].&lt;/p&gt;

&lt;p&gt;Finally, i replicate the nextState function 80 times so that i can pass it to &lt;code&gt;sequeunce&lt;/code&gt; so that it'll fit the shape required by &lt;code&gt;S.execute&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;S.execute(initial)(A.sequence(S.Applicative)(A.replicate(80, nextState)))&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;This was okay with the small dataset however I suspect due to the eager evaluation of JS and the nature of A.sequence, my browser tab crashed on the input dataset. So, instead I'm going to use reduce instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipe(A.replicate(80, nextState), A.reduce(initial, (state, f) =&amp;gt; S.execute(state)(f))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit: I don't think the problem was due to using sequence or changing it to reduce. It may be something to do with console logging an array several hundred thousand long as the answer shows up before the tab crashes. Changing it to only print out the length of the array seems to work okay&lt;/p&gt;

&lt;p&gt;Part 2:&lt;br&gt;
Now we are assessing the number of fish after 256 days instead of 80, so only a simple change from 80 -&amp;gt; 256.&lt;/p&gt;

&lt;p&gt;Edit 2: So it appears its not that simple as the brute force method is too slow and memory intensive. Instead, I am going to remodel my state to be an array where the index is the number of days left and the value is the number of fish with that index. The beauty of using the State monad pattern is that even though i have changed the representation of the State as well as the nextState transformation, the passing of one state to the next remained the same.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/laughing-smoke-zehut?file=/src/index.ts"&gt;https://codesandbox.io/s/laughing-smoke-zehut?file=/src/index.ts&lt;/a&gt;&lt;/p&gt;

</description>
      <category>functional</category>
      <category>typescript</category>
      <category>adventofcode</category>
    </item>
    <item>
      <title>Advent of code 2021 - day 5</title>
      <dc:creator>Derp</dc:creator>
      <pubDate>Thu, 06 Jan 2022 11:37:38 +0000</pubDate>
      <link>https://dev.to/derp/advent-of-code-2021-day-5-3i4i</link>
      <guid>https://dev.to/derp/advent-of-code-2021-day-5-3i4i</guid>
      <description>&lt;p&gt;This challenge gives us a list of start &amp;amp; end co-ordinates and asks us to count the intersections. Looking at the input, it seems that all the co-ordinates are less than 1000. For part 1, we are ignoring co-ordinates which aren't horizontal or vertical.&lt;/p&gt;

&lt;p&gt;My strategy is to map each start &amp;amp; end co-ordinate into a set of points. So (1,1) -&amp;gt; (1,3) gets transformed into list containing (1,1), (1,2), (1,3). I will then map that list of list of co-ordinates into a Map of co-ordinates and a count. In type signatures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Coord = [number, number]
type Line = [Coord, Coord]

toCoords:: Line -&amp;gt; List Coord
countIntersections:: List Coord -&amp;gt; Map (Coord, number)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit: I spent a lot of time trying to write a range function and went down a generator function rabbithole. I also goofed up trying to make the countIntersection function work with a Set instead of realising later that what i really needed was a Map.&lt;/p&gt;

&lt;p&gt;Edit 2: So exploding out each line into an array of Coords is not good for the computer. Even though the above approach works for the example, the input is simply too large. My next approach is to fold over the input array so that the JS GC can get rid the exploded array for each line.&lt;/p&gt;

&lt;p&gt;Edit 3: I suspect that the &lt;code&gt;export declare const upsertAt: &amp;lt;K&amp;gt;(E: Eq&amp;lt;K&amp;gt;) =&amp;gt; &amp;lt;A&amp;gt;(k: K, a: A) =&amp;gt; (m: Map&amp;lt;K, A&amp;gt;) =&amp;gt; Map&amp;lt;K, A&amp;gt;&lt;br&gt;
&lt;/code&gt; function is causing a bit of grief with performance. I think that the process of making this a pure function involves taking in a map, making an edit and then recreating the entire map which is causing a severe slow down.&lt;/p&gt;

&lt;p&gt;Edit 4: I give up using a non-standard key requiring an Eq instance to figure out the difference between the keys. I'm going to stringify the coord and use that as the key.&lt;/p&gt;

&lt;p&gt;-- Part 2&lt;br&gt;
Part 2 asks us to take into account lines which aren't horizontal or vertical. This is a fairly easy addition.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/quizzical-raman-lz0yx?file=/src/index.ts"&gt;https://codesandbox.io/s/quizzical-raman-lz0yx?file=/src/index.ts&lt;/a&gt;&lt;/p&gt;

</description>
      <category>functional</category>
      <category>typescript</category>
      <category>adventofcode</category>
    </item>
    <item>
      <title>Advent of code 2021 - day 4</title>
      <dc:creator>Derp</dc:creator>
      <pubDate>Wed, 29 Dec 2021 04:15:59 +0000</pubDate>
      <link>https://dev.to/derp/advent-of-code-day-4-4cpo</link>
      <guid>https://dev.to/derp/advent-of-code-day-4-4cpo</guid>
      <description>&lt;p&gt;Part 1:&lt;/p&gt;

&lt;p&gt;We are playing simultaneous bingo where we have an array of numbers being called out as well as several matricies of bingo cards. We then need to identify which matrix has the bingo and sum up the remaining uncalled numbers.&lt;/p&gt;

&lt;p&gt;So whenever a new number is called out, for each board, we Either get a Incomplete board or a Bingo Board. This translates to a function signature of &lt;code&gt;number -&amp;gt; Incomplete Board -&amp;gt;  Either (Bingo Board) (Incomplete Board)&lt;/code&gt;. Using &lt;code&gt;sequence&lt;/code&gt; we can turn our array of Eithers into Either a Bingo Board or an array of Incomplete Board. &lt;code&gt;sequeunce:: Monad m =&amp;gt; [m a] -&amp;gt; m [a]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;There were two things that tripped me up in part 1 of this challenge though, the first was the parsing of the input. In previous challenges, I did it manually via search/replace and regex to turn it into arrays or what not. With this challenge, i accidentally chopped off a few digits in my example array causing the wrong answer to show up. Thankfully, I created a &lt;code&gt;show&lt;/code&gt; function for debugging which enabled me to pick this error up quickly.&lt;/p&gt;

&lt;p&gt;The second thing which tripped me up was the signature of fold&lt;br&gt;
&lt;code&gt;export declare const fold: &amp;lt;E, A, B&amp;gt;(onLeft: (e: E) =&amp;gt; B, onRight: (a: A) =&amp;gt; B) =&amp;gt; (ma: Either&amp;lt;E, A&amp;gt;) =&amp;gt; B&lt;/code&gt;. I had previously used &lt;code&gt;identity&lt;/code&gt; as the onLeft function, however that sets the return type &lt;code&gt;B&lt;/code&gt; and this caused a type error when i returned an Either for my onRight function. After realising my error, I returned an Either for my onLeft function.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;E.fold(&lt;br&gt;
    (complete) =&amp;gt; E.left(complete),&lt;br&gt;
    (incompletes) =&amp;gt; play(rest)(incompletes)&lt;br&gt;
  )&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;-- Part 2&lt;br&gt;
Instead of returning the first bingo board, we want to return the &lt;em&gt;last&lt;/em&gt; bingo board. We used &lt;code&gt;sequence&lt;/code&gt; in part one which eagerly evaluates the first Left. Now in Part 1, &lt;code&gt;sequence&lt;/code&gt; works because we stop immediately when we have found our winning bingo game so the return type of Either Complete Incomplete [] makes sense. However in part 2, it is not one or the other, we need both until we finish going through all the bingo numbers to find the &lt;em&gt;last&lt;/em&gt; winning bingo board. Hence we need a return type of (Option&amp;lt;(number, Complete)&amp;gt;, Incomplete[]) representing the last winning bingo number and bingo board and the remaining list of incomplete boards. (This thought occurred to me several days later).&lt;/p&gt;

&lt;p&gt;My strategy is to create a playLast function with the signature&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  playLast:: number -&amp;gt; Incomplete[] -&amp;gt; (Option&amp;lt;(number,Complete)&amp;gt;, Incomplete[])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;playLast also has the interesting situation where you might have several winning bingo games at the same time. To tackle this, I partitioned the &lt;code&gt;partitionMap&lt;/code&gt; function which has as similar signature to &lt;code&gt;partitionEithers:: [Either a b] -&amp;gt; ([a], [b])&lt;/code&gt;. I then return the head of the Completed games.&lt;/p&gt;

&lt;p&gt;When reducing over my bingo numbers, I needed to figure out a way of joining my two Option&amp;lt;(number,Complete)&amp;gt; together such that the last Some &lt;code&gt;won&lt;/code&gt;. To do this, I created a Monoid over Options&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const getLastSome = O.getMonoid&amp;lt;any&amp;gt;(S.last());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the  required to make it work as without it as without it, typescript substitutes &lt;code&gt;never&lt;/code&gt; into there and it won't work with any Options. &lt;/p&gt;

&lt;p&gt;Also sometimes the typescript compiler complains unless you use &lt;code&gt;pipe&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/jolly-flower-5o78i?file=/src/index.ts"&gt;https://codesandbox.io/s/jolly-flower-5o78i?file=/src/index.ts&lt;/a&gt;&lt;/p&gt;

</description>
      <category>adventofcode</category>
      <category>functional</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Advent of code 2021 - day 3</title>
      <dc:creator>Derp</dc:creator>
      <pubDate>Wed, 15 Dec 2021 12:37:10 +0000</pubDate>
      <link>https://dev.to/derp/advent-of-code-2021-day-3-4ga9</link>
      <guid>https://dev.to/derp/advent-of-code-2021-day-3-4ga9</guid>
      <description>&lt;p&gt;&lt;a href="https://adventofcode.com/2021/day/3"&gt;https://adventofcode.com/2021/day/3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Day 3 wants us to calculate the most common bit for each index value in a list of strings. We will then turn that string into binary and do some mathematical operations with it. Ie&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00100
11110
10110
10111
10101
01111
00111
11100
10000
11001
00010
01010
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will turn into 10110 which is 22 in decimal.&lt;/p&gt;

&lt;p&gt;To tackle this, I am going to reduce the binary string array into a count of how many 1s for each position. So using the above example, that would reduce down to &lt;code&gt;[7,5,8,7,5]&lt;/code&gt;. Since I also know the length of the array, if the count is larger than &lt;code&gt;length/2&lt;/code&gt; then I know that binary value for that index should be 1. From there I can work out the binary string and finally the decimal value.&lt;/p&gt;

&lt;p&gt;Part 2 is a bit trickier. Instead of a single pass through the array, it requires us to recursively reduce the array by:&lt;br&gt;
1) Start from the first position&lt;br&gt;
2) If the array only has one element, this is the value&lt;br&gt;
3) From the existing array, look at the most common bit in the current position&lt;br&gt;
4) Filter the array to only include the elements that have that bit value in that index&lt;br&gt;
5) Go back to 2) with the remaining array and increment the position by one.&lt;/p&gt;

&lt;p&gt;This problem is well suited for a recursive function.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/gracious-leaf-qjotm"&gt;https://codesandbox.io/s/gracious-leaf-qjotm&lt;/a&gt;&lt;/p&gt;

</description>
      <category>functional</category>
      <category>typescript</category>
      <category>adventofcode</category>
    </item>
    <item>
      <title>Advent of Code 2021 - day 2</title>
      <dc:creator>Derp</dc:creator>
      <pubDate>Mon, 13 Dec 2021 12:50:12 +0000</pubDate>
      <link>https://dev.to/derp/advent-of-code-2021-51n0</link>
      <guid>https://dev.to/derp/advent-of-code-2021-51n0</guid>
      <description>&lt;p&gt;&lt;a href="https://adventofcode.com/2021/day/2"&gt;https://adventofcode.com/2021/day/2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Day 2 appears to be a parsing problem. So given&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forward 5
down 5
forward 8
up 3
down 8
forward 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We want to increment the X co-ordinate when going forwards and either increment the Y co-ordinate when going up or down.&lt;/p&gt;

&lt;p&gt;To solve this, I am first going to map my strings into tuples representing the change in X or Y. So down 5 gets translated into (0, -5). I am also going to create a monoid under sum and fold over my tuple array to get my final change in X and Y.&lt;/p&gt;

&lt;p&gt;-- Part 2&lt;br&gt;
This introduces an aim concept. To solve this, I am re-using the tuple mapping from part 1 and I will need a reducing function that takes in a current [horizontal, depth, aim] and a [forward, updown] tuple and produces a new [horizontal', depth', aim'] tuple.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/reverent-fast-ytbx3"&gt;https://codesandbox.io/s/reverent-fast-ytbx3&lt;/a&gt;&lt;/p&gt;

</description>
      <category>functional</category>
      <category>typescript</category>
      <category>adventofcode</category>
    </item>
    <item>
      <title>Advent of Code 2021 - day 1</title>
      <dc:creator>Derp</dc:creator>
      <pubDate>Sun, 12 Dec 2021 22:16:38 +0000</pubDate>
      <link>https://dev.to/derp/advent-of-code-2021-239m</link>
      <guid>https://dev.to/derp/advent-of-code-2021-239m</guid>
      <description>&lt;p&gt;&lt;a href="https://adventofcode.com/2021/day/1"&gt;https://adventofcode.com/2021/day/1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Given a list of numbers, we are asked how many times the next number in the list is larger than the previous. Ie&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;199 (N/A - no previous measurement)
200 (increased)
208 (increased)
210 (increased)
200 (decreased)
207 (increased)
240 (increased)
269 (increased)
260 (decreased)
263 (increased)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can be solved by reducing over the array returning back a pair of &lt;code&gt;(lastNumber, count)&lt;/code&gt; in the reduction function. For the starting condition, I want to use Number.NaN to ensure that I do not increase the count for the first iteration.&lt;/p&gt;

&lt;p&gt;-- Part 2&lt;br&gt;
This time, instead of measuring the difference between individual measurements, we are now measuring a sliding window of three values. Ie in the first example, we measure whether &lt;code&gt;[199, 200, 208]&lt;/code&gt; is larger than &lt;code&gt;[200, 208, 210]&lt;/code&gt;. Since the only difference between these two frames are the numbers at the front and the end, I am going to use a comparison function that takes in four numbers and compares the first and last numbers which should tell me if there is an increase or not. I will then move my sliding window of four over the original list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/amazing-satoshi-zbcs7?file=/src/index.ts"&gt;https://codesandbox.io/s/amazing-satoshi-zbcs7?file=/src/index.ts&lt;/a&gt;&lt;/p&gt;

</description>
      <category>functional</category>
      <category>typescript</category>
      <category>adventofcode</category>
    </item>
    <item>
      <title>Requirements engineering</title>
      <dc:creator>Derp</dc:creator>
      <pubDate>Wed, 17 Nov 2021 00:37:06 +0000</pubDate>
      <link>https://dev.to/derp/requirements-engineering-hgg</link>
      <guid>https://dev.to/derp/requirements-engineering-hgg</guid>
      <description>&lt;p&gt;Disclaimer: I am not a professional business analyst&lt;/p&gt;

&lt;p&gt;I have been involved in a few projects and I have always followed a similar pattern into getting them to completion. I have broken down the process into different phases and although this may initially read like waterfall, in reality, it is a lot more collaborative as we try and find the hidden requirements through conversations rather than documentation.&lt;br&gt;
 This post is an effort to jot down a few notes and hopefully give readers a few things to think about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem Discovery
&lt;/h2&gt;

&lt;p&gt;·       Understanding the constraints of the problem both technical and social&lt;br&gt;
·       Discovering the different stakeholder(s) requirements both explicit and contextual&lt;/p&gt;

&lt;p&gt;We can't build the right thing if we do not understand the context in which the thing has to exist in. This can be both technical and social. Technical questions to ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who's going to use this?&lt;/li&gt;
&lt;li&gt;What other software are they familiar with?&lt;/li&gt;
&lt;li&gt;If we build it, how will it be deployed?&lt;/li&gt;
&lt;li&gt;Who will maintain it going forward?&lt;/li&gt;
&lt;li&gt;What technology stacks are the future maintainers comfortable with?&lt;/li&gt;
&lt;li&gt;Have the future maintainers been told that they will maintain it yet? Did they agree?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Social questions to ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which organisation(s) are funding this?&lt;/li&gt;
&lt;li&gt;Why are they funding this?&lt;/li&gt;
&lt;li&gt;Who will be the primary decision maker(s)?&lt;/li&gt;
&lt;li&gt;What are the main motivators for the primary decision makers(s)? Keep in mind that the motivations of the human decision makers are different to the broader motivations of an organisation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Solution proposal
&lt;/h2&gt;

&lt;p&gt;·       Iteratively propose and refine solutions with the client usually with wireframes&lt;br&gt;
·       Arrive at a loose, shared conceptual agreement of what will be delivered&lt;/p&gt;

&lt;p&gt;Hopefully after the problem discovery phase, you will have identified the primary decision maker(s). The goal of this stage is to reach a loose, shared conceptual agreement of what will be delivered and my favorite way of reaching that is through low fidelity wireframes using &lt;a href="http://pencil.evolus.vn/"&gt;Pencil&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;There are a few benefits to creating wireframes. Firstly, you can map it against your existing or hypothetical API to see whether or not your things is possible or not. Secondly, you can show them to clients and in seeing something visual, they can much more easily where you have missed key concepts and why it won't work for their use case. As it is easy to iterate on wireframes, you can incorporate their feedback to come up with new designs to meet their use cases. This has the very very important effect of making the client feel listened to which goes a long way to establishing trust. Furthermore, as the client sees their changes make their way onto the wireframes, they gain incrementally more ownership of it which may help increase the emotional attachment they have to the project.&lt;/p&gt;

&lt;p&gt;After a few iterations, if there are no more major changes, then you can be fairly certain that you have reached the "loose, shared conceptual agreement" goal and the project can move onto the next phase. &lt;/p&gt;

&lt;h2&gt;
  
  
  Project delivery
&lt;/h2&gt;

&lt;p&gt;·       Set up architecture based on the skills/interests of the team&lt;br&gt;
·       Incrementally deliver and demonstrate developed functionality&lt;br&gt;
·       Negotiate and prioritise additional or changed client requirements as they are discovered&lt;/p&gt;

&lt;p&gt;When choosing your technology stack, the most important thing to consider are the skills and interests of your team. I usually like to follow a very loose scrum process where we have standup to ensure that people aren't blocked for more than a day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Post project
&lt;/h2&gt;

&lt;p&gt;·       Document lessons learnt&lt;br&gt;
·       Advise on possible futures for the delivered project seeding future collaboration opportunities&lt;/p&gt;

&lt;p&gt;After the end of the project, it is important to hold a retrospective style meeting and to document the lessons learnt. By writing these down, it both increases your understanding of what went well or didn't go well and makes it available for other people to view thereby increasing the knowledge within your organisation.&lt;/p&gt;

&lt;p&gt;It may also be helpful to have a more imaginative session with the team and the client where you muse on possible futures of your project. Although the money may not be available now, these seeds may fruit into future collaboration opportunities.&lt;/p&gt;

</description>
      <category>leadership</category>
    </item>
  </channel>
</rss>
