<?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: Ken Aguilar</title>
    <description>The latest articles on DEV Community by Ken Aguilar (@piq9117).</description>
    <link>https://dev.to/piq9117</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%2F51431%2Fd9ddca48-b5fe-475d-80a6-9b394d9599ed.jpg</url>
      <title>DEV Community: Ken Aguilar</title>
      <link>https://dev.to/piq9117</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/piq9117"/>
    <language>en</language>
    <item>
      <title>Haskell - Enforcing Naming Convention with Parsec</title>
      <dc:creator>Ken Aguilar</dc:creator>
      <pubDate>Sat, 05 Sep 2020 02:01:25 +0000</pubDate>
      <link>https://dev.to/piq9117/haskell-enforcing-naming-convention-with-parsec-1f2h</link>
      <guid>https://dev.to/piq9117/haskell-enforcing-naming-convention-with-parsec-1f2h</guid>
      <description>&lt;p&gt;In my project &lt;a href="https://taezos.org/taezos/migratum"&gt;migratum&lt;/a&gt; I wanted to enforce a naming convention like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;V&amp;lt;version number&amp;gt;__&amp;lt;file name&amp;gt;.sql
+       +         +     +     + +
|       |         |     |     | |
|       |         |     |     | v
|       |         |     |     | Enforce sql extension.
|       |         |     |     v
|       |         |     |     Enforce this dot to indicate the end of the file name.
|       |         |     v
|       |         |     File name need to be alpha numeric. No other symbols, except underscore
|       |         v
|       |         Enforce the double underscore
|       v
|       Version number have to be numbers.
v
Enforce the V character to signify &lt;span class="s2"&gt;"version"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Ways I can accomplish these are with&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Regex&lt;/li&gt;
&lt;li&gt;Parser Combinators&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm not sure how to do this with regex because to be honest, I know very simple regex and I don't have a &lt;a href="https://regexlicensing.org/"&gt;regex license&lt;/a&gt;. I'm decent with parser combinators and plus it's the title of this blog post, so that's what I'm going to use to accomplish the task I set out for.&lt;/p&gt;

&lt;p&gt;Parser combinators really shine when you parse something recursive like &lt;code&gt;json&lt;/code&gt;. You know how &lt;code&gt;json&lt;/code&gt; can contain an array and objects and then these objects and arrays can contain arrays and objects, so on and so forth? Yeah, parser combinators are really neat for that. So don't judge parser combinators solely on this blog post. I chose parser combinators because it's my go-to method for parsing, and I personally think they're convenient.&lt;/p&gt;

&lt;p&gt;Before we touch parsing, let's create a type representation of the file name based on the ascii diagram above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;FilenameStructure&lt;/span&gt; 
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;FilenameStructure&lt;/span&gt; &lt;span class="kt"&gt;FileVersion&lt;/span&gt; &lt;span class="kt"&gt;Underscore&lt;/span&gt; &lt;span class="kt"&gt;Underscore&lt;/span&gt; &lt;span class="kt"&gt;FileName&lt;/span&gt; &lt;span class="kt"&gt;Dot&lt;/span&gt; &lt;span class="kt"&gt;FileExtension&lt;/span&gt;
  &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Show&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="kt"&gt;FileVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;FileVersion&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
  &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Show&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="kt"&gt;Underscore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Underscore&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
  &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Show&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="kt"&gt;FileName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;FileName&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
  &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Show&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="kt"&gt;Dot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Dot&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
  &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Show&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="kt"&gt;FileExtension&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;FileExtension&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
  &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Show&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 can focus on specific segments of the file name instead of thinking of parsing the entire file name. I think that makes it a bit easier. At least to me  it does. I can think of parsing the file version, underscore, filename, etc individually.&lt;/p&gt;

&lt;p&gt;Let's start with the imports. Popular libraries that come to mind are parsec, megaparsec, and attoparsec. Evaluate which one suits your project, but on this blog post we're using parsec.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- parsec&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;Text.ParserCombinators.Parsec&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;GenParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;ParseError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="k"&gt;qualified&lt;/span&gt; &lt;span class="nn"&gt;Text.ParserCombinators.Parsec&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Parsec&lt;/span&gt;

&lt;span class="c1"&gt;-- text&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="k"&gt;qualified&lt;/span&gt; &lt;span class="nn"&gt;Data.Text&lt;/span&gt;                     &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's start with the file version parser. Our convention says that we need to start with the character &lt;code&gt;V&lt;/code&gt;, then it should be followed by numbers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;fileVersionParser&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;GenParser&lt;/span&gt; &lt;span class="kt"&gt;Char&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="kt"&gt;FileVersion&lt;/span&gt;
&lt;span class="n"&gt;fileVersionParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;vChar&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kt"&gt;Parsec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="sc"&gt;'V'&lt;/span&gt;
  &lt;span class="n"&gt;vNum&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kt"&gt;Parsec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;digit&lt;/span&gt;
  &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kt"&gt;FileVersion&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;vChar&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;vNum&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If we try this in &lt;code&gt;ghci&lt;/code&gt; it will look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;ghci&amp;gt; import Text.ParserCombinators.Parsec
ghci&amp;gt; parse fileVersionParser &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="s2"&gt;"V69"&lt;/span&gt;
ghci&amp;gt; Right &lt;span class="o"&gt;(&lt;/span&gt; FileVersion &lt;span class="s2"&gt;"V69"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's what we want, to match &lt;code&gt;Right&lt;/code&gt; and return our &lt;code&gt;FileVersion&lt;/code&gt; with &lt;br&gt;
the text "V69".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;ghci&amp;gt; parse fileVersionParser &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="s2"&gt;"Vwhat"&lt;/span&gt;
ghci&amp;gt; Left &lt;span class="o"&gt;(&lt;/span&gt;line 1, column2&lt;span class="o"&gt;)&lt;/span&gt;:
unexpected &lt;span class="s2"&gt;"w"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's right, it should fail when there's no version number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;ghci&amp;gt; parse fileVersionParser &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="s2"&gt;"V1what"&lt;/span&gt;
ghci&amp;gt; Right &lt;span class="o"&gt;(&lt;/span&gt; FileVersion &lt;span class="s2"&gt;"V1"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It drops the input that isn't a number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;ghci&amp;gt; parse fileVersionParser &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="s2"&gt;"what"&lt;/span&gt;
ghci&amp;gt; Left &lt;span class="o"&gt;(&lt;/span&gt;line 1, column 1&lt;span class="o"&gt;)&lt;/span&gt;:
unexpected &lt;span class="s2"&gt;"w"&lt;/span&gt;
expecting &lt;span class="s2"&gt;"V"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Finally, it will fail if it doesn't find the "V" character.&lt;/p&gt;

&lt;p&gt;Woohoo! One parser down, four to go!&lt;/p&gt;

&lt;p&gt;Let's do the rest of the parsers, and feel free to try these out in &lt;code&gt;ghci&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;underscoreParser&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;GenParser&lt;/span&gt; &lt;span class="kt"&gt;Char&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="kt"&gt;Underscore&lt;/span&gt;
&lt;span class="n"&gt;underscoreParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Underscore&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Parsec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;satisfy&lt;/span&gt; &lt;span class="n"&gt;isUnderscore&lt;/span&gt;

&lt;span class="n"&gt;isUnderscore&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Char&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;
&lt;span class="n"&gt;isUnderscore&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"_"&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;fileNameParser&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;GenParser&lt;/span&gt; &lt;span class="kt"&gt;Char&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="kt"&gt;FileName&lt;/span&gt;
&lt;span class="n"&gt;fileNameParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;FileName&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt; 
  &lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Parsec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;many&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Parsec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alphaNum&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Parsec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;satisfy&lt;/span&gt; &lt;span class="n"&gt;isUnderscore&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;dotParser&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;GenParser&lt;/span&gt; &lt;span class="kt"&gt;Char&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="kt"&gt;Dot&lt;/span&gt;
&lt;span class="n"&gt;dotParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Dot&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="sc"&gt;'.'&lt;/span&gt;

&lt;span class="n"&gt;fileExtensionParser&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;GenParser&lt;/span&gt; &lt;span class="kt"&gt;Char&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="kt"&gt;FileExtension&lt;/span&gt;
&lt;span class="n"&gt;fileExtensionParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;FileExtension&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Parsec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="s"&gt;"sql"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then, to create a parser for the whole file name we combine the rest of our parsers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;filenameStructureParser&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;GenParser&lt;/span&gt; &lt;span class="kt"&gt;Char&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="kt"&gt;FilenameStructure&lt;/span&gt;
&lt;span class="n"&gt;filenameStructureParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;FilenameStructure&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fileVersionParser&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;underscoreParser&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;underscoreParser&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fileNameParser&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dotParser&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fileExtensionParser&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can also do this with the &lt;code&gt;do&lt;/code&gt; syntax if that's more convenient.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;filenameStructureParser&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;GenParser&lt;/span&gt; &lt;span class="kt"&gt;Char&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="kt"&gt;FilenameStructure&lt;/span&gt;
&lt;span class="n"&gt;filenameStructureParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;fileVersionParser&lt;/span&gt;
  &lt;span class="n"&gt;u1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;underscoreParser&lt;/span&gt;
  &lt;span class="n"&gt;u2&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;underscoreParser&lt;/span&gt;
  &lt;span class="n"&gt;fileName&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;fileNameParser&lt;/span&gt;
  &lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;dotParser&lt;/span&gt;
  &lt;span class="n"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;fileExtensionParser&lt;/span&gt;
  &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kt"&gt;FilenameStructure&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="n"&gt;u1&lt;/span&gt; &lt;span class="n"&gt;u2&lt;/span&gt; &lt;span class="n"&gt;fileName&lt;/span&gt; &lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Finally, our parser "runner"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;namingConvention&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Either&lt;/span&gt; &lt;span class="kt"&gt;ParseError&lt;/span&gt; &lt;span class="kt"&gt;FilenameStructure&lt;/span&gt;
&lt;span class="n"&gt;namingConvention&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="kt"&gt;Parsec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt; &lt;span class="n"&gt;filenameStructureParser&lt;/span&gt; &lt;span class="s"&gt;"Error: Not following naming convention"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Instead of manually trying them out in &lt;code&gt;ghci&lt;/code&gt; we can instead do some unit testing. So we don't have to keep messing with the terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;NamingConventionSpec&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Test.Hspec&lt;/span&gt;

&lt;span class="n"&gt;spec&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Spec&lt;/span&gt;
&lt;span class="n"&gt;spec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;desribe&lt;/span&gt; &lt;span class="s"&gt;"Filename"&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s"&gt;"follows naming convention"&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;successResult&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;namingConvention&lt;/span&gt; &lt;span class="s"&gt;"V1__uuid_extension.sql"&lt;/span&gt;
      &lt;span class="n"&gt;emptyFileName&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;namingConvention&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
      &lt;span class="n"&gt;noExtension&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;namingConvention&lt;/span&gt; &lt;span class="s"&gt;"V1__uuid_extension"&lt;/span&gt;
      &lt;span class="n"&gt;noVersion&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;namingConvention&lt;/span&gt; &lt;span class="s"&gt;"uuid_extension.sql"&lt;/span&gt;
      &lt;span class="n"&gt;upperCaseFileName&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;namingConvention&lt;/span&gt; &lt;span class="s"&gt;"V1_UUID_extension.sql"&lt;/span&gt;
      &lt;span class="n"&gt;symbolFileName&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;namingConvention&lt;/span&gt; &lt;span class="s"&gt;"V1_UUID+extension.sql"&lt;/span&gt;

      &lt;span class="c1"&gt;-- success cases&lt;/span&gt;
      &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="n"&gt;successResult&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Right&lt;/span&gt; &lt;span class="s"&gt;"V1__uuid_extension.sql"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="n"&gt;upperCaseFileName&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Right&lt;/span&gt; &lt;span class="s"&gt;"V1__UUID_extension.sql"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;-- failure cases&lt;/span&gt;
      &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;isLeft&lt;/span&gt; &lt;span class="n"&gt;emptyFileName&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;True&lt;/span&gt;
      &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;isLeft&lt;/span&gt; &lt;span class="n"&gt;noFileExt&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;True&lt;/span&gt;
      &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;isLeft&lt;/span&gt; &lt;span class="n"&gt;noVersion&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;True&lt;/span&gt;
      &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;isLeft&lt;/span&gt; &lt;span class="n"&gt;symbolFilename&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now that we have our parser we can use it check for duplicates, because our types have an &lt;code&gt;Eq&lt;/code&gt; instance we can do equality checking.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;fileVersion&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;FilenameStructure&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;FileVersion&lt;/span&gt;
&lt;span class="n"&gt;fileVersion&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;FilenameStructure&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;

&lt;span class="n"&gt;getVersion&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Either&lt;/span&gt; &lt;span class="kt"&gt;ParseError&lt;/span&gt; &lt;span class="kt"&gt;FilenameStructure&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Either&lt;/span&gt; &lt;span class="kt"&gt;ParseError&lt;/span&gt; &lt;span class="kt"&gt;FileVersion&lt;/span&gt;
&lt;span class="n"&gt;getVersion&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
  &lt;span class="kt"&gt;Left&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Left&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
  &lt;span class="kt"&gt;Right&lt;/span&gt; &lt;span class="n"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Right&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;fileVersion&lt;/span&gt; &lt;span class="n"&gt;fs&lt;/span&gt;

&lt;span class="n"&gt;checkDuplicate&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Either&lt;/span&gt; &lt;span class="kt"&gt;ParseError&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;checkDuplicate&lt;/span&gt; &lt;span class="n"&gt;filenames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;versions&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;traverse&lt;/span&gt; &lt;span class="n"&gt;getVersion&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;namingConvention&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;filenames&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;anySame&lt;/span&gt; &lt;span class="n"&gt;versions&lt;/span&gt;
    &lt;span class="c1"&gt;-- Express your errors however you want, this is just to show that this is &lt;/span&gt;
    &lt;span class="c1"&gt;-- the error branch.&lt;/span&gt;
    &lt;span class="kr"&gt;then&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="s"&gt;"Duplicate migration file"&lt;/span&gt;
    &lt;span class="kr"&gt;else&lt;/span&gt; &lt;span class="kt"&gt;Right&lt;/span&gt; &lt;span class="n"&gt;filenames&lt;/span&gt;
  &lt;span class="kr"&gt;where&lt;/span&gt;
    &lt;span class="n"&gt;anySame&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Eq&lt;/span&gt; &lt;span class="n"&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="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;
    &lt;span class="n"&gt;anySame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;isSeen&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt;

    &lt;span class="n"&gt;isSeen&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Eq&lt;/span&gt; &lt;span class="n"&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="n"&gt;a&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="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;
    &lt;span class="n"&gt;isSeen&lt;/span&gt; &lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt; &lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;isSeen&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;
    &lt;span class="n"&gt;isSeen&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When creating your parsers, avoid doing any validation or any "smart" logic. Concentrate on parsing the input and nothing more. Once you have your parsers then you can do whatever you want with the output.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://haskellbook.com/"&gt;Haskell from First Principles&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.cs.nott.ac.uk/~pszgmh/monparsing.pdf"&gt;Monadic Parser Combinators&lt;/a&gt;&lt;/p&gt;

</description>
      <category>haskell</category>
      <category>parsing</category>
      <category>functional</category>
    </item>
    <item>
      <title>Haskell - Look Ma! No Concrete Implementation!</title>
      <dc:creator>Ken Aguilar</dc:creator>
      <pubDate>Sun, 09 Aug 2020 07:04:24 +0000</pubDate>
      <link>https://dev.to/piq9117/haskell-look-ma-no-concrete-implementation-32p8</link>
      <guid>https://dev.to/piq9117/haskell-look-ma-no-concrete-implementation-32p8</guid>
      <description>&lt;p&gt;This is my post about tagless final encoding. There are many like it, but this one is mine. My tagless final encoding post is my best friend. It is my life. I must master it as I must master my life.&lt;/p&gt;

&lt;p&gt;I can't think of a good intro so I modified the Rifleman's Creed. Anyway, the tagless final encoding technique has been very helpful in structuring my programs without being burdened about dependencies so much, because of this I can change dependencies and mostly don't have to re-structure my program. This technique also makes it almost effortless to do unit testing.&lt;/p&gt;

&lt;p&gt;Just like my other posts let's do a &lt;a href="https://taezos.org/piq9117/notes-examples/src/branch/master/tagless-transform"&gt;contrived example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is our user story.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A command line tool that takes a file path to a text file that contains some text.&lt;/li&gt;
&lt;li&gt;The content of the input file will be processed, and the text content will be capitalized.&lt;/li&gt;
&lt;li&gt;The processed text content will then be printed to an output file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's start by creating the representation of our application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="cp"&gt;{-# LANGUAGE DerivingStrategies         #-}&lt;/span&gt;
&lt;span class="cp"&gt;{-# LANGUAGE GeneralizedNewtypeDeriving #-}&lt;/span&gt;
&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;AppM&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;runAppM&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Functor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Applicative&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Monad&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;MonadIO&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then, let's define the capabilities of the app based on the made up user story. First, the cli capability.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Capability.CLI&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Monad&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;ManageCLI&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="n"&gt;parseCliCommand&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt;
  &lt;span class="n"&gt;interpretCLI&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;

&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;commandInput&lt;/span&gt;  &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;commandOutput&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Show&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, the capabalities to manipulate files in the file system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Capability.File&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Monad&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;ManageFile&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="n"&gt;getFileContent&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
  &lt;span class="n"&gt;printContent&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Finally, the capability to manipulate text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Capability.TextContent&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Monad&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;ManageTextContent&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="n"&gt;capitalizeContent&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With all these capabilities, I think we are ready to assemble our program. So, let's go back to the &lt;code&gt;AppM&lt;/code&gt; module. We have to create instances but skip the implementation for now, and use &lt;code&gt;undefined&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="cp"&gt;{-# LANGUAGE DerivingStrategies         #-}&lt;/span&gt;
&lt;span class="cp"&gt;{-# LANGUAGE GeneralizedNewtypeDeriving #-}&lt;/span&gt;
&lt;span class="cp"&gt;{-# LANGUAGE InstanceSigs               #-}&lt;/span&gt;
&lt;span class="cp"&gt;{-# LANGUAGE RecordWildCards            #-}&lt;/span&gt;
&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;AppM&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;Capability.CLI&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;Capability.File&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;Capability.TextContent&lt;/span&gt;

&lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;runAppM&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Functor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Applicative&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Monad&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;MonadIO&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;startApp&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;startApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;runAppM&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;interpretCLI&lt;/span&gt; &lt;span class="o"&gt;=&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;parseCliCommand&lt;/span&gt;

&lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="kt"&gt;ManageCLI&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="n"&gt;parseCliCommand&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt;
  &lt;span class="n"&gt;parseCliCommand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;undefined&lt;/span&gt;

  &lt;span class="n"&gt;interpretCLI&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;interpretCLI&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;getFileContent&lt;/span&gt; &lt;span class="n"&gt;commandInput&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;capitalizeContent&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;
    &lt;span class="n"&gt;printContent&lt;/span&gt; &lt;span class="n"&gt;commandOutput&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;

&lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="kt"&gt;ManageFile&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="n"&gt;getFileContent&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
  &lt;span class="n"&gt;getFileContent&lt;/span&gt; &lt;span class="n"&gt;filePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;undefined&lt;/span&gt;

  &lt;span class="n"&gt;printContent&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;printContent&lt;/span&gt; &lt;span class="n"&gt;outputPath&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;undefined&lt;/span&gt;

&lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="kt"&gt;ManageTextContent&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="n"&gt;capitalizeContent&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
  &lt;span class="n"&gt;capitalizeContent&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;undefined&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see we were able to assemble our program in &lt;code&gt;interpretCLI&lt;/code&gt; without any concrete implementations. When we provide the concrete implementations, we won't get so bogged down by thinking about the entire the program because we've already done that. We only have to think about the concrete implementation of individual capabilities. For example, we just need to think about how to retrieve a file, print a file, etc.&lt;/p&gt;

&lt;p&gt;Proceeding to our concrete implementation we can pick &lt;code&gt;optparse-applicative&lt;/code&gt; as our cli utility and &lt;code&gt;relude&lt;/code&gt; as our prelude.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;AppM&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;Relude&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="k"&gt;qualified&lt;/span&gt; &lt;span class="nn"&gt;Data.Text&lt;/span&gt;              &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;Options.Applicative&lt;/span&gt;

&lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="kt"&gt;ManageCLI&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="n"&gt;parseCliCommand&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt;
  &lt;span class="n"&gt;parseCliCommand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;liftIO&lt;/span&gt; 
    &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;execParser&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;helper&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;parseCommand&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;fullDesc&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;interpretCLI&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;interpretCLI&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;getFileContent&lt;/span&gt; &lt;span class="n"&gt;commandInput&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;capitalizeContent&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;
    &lt;span class="n"&gt;printContent&lt;/span&gt; &lt;span class="n"&gt;commandOutput&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;

&lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="kt"&gt;ManageFile&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="n"&gt;getFileContent&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
  &lt;span class="n"&gt;getFileContent&lt;/span&gt; &lt;span class="n"&gt;filePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readFileText&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unpack&lt;/span&gt; &lt;span class="n"&gt;filePath&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;printContent&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;printContent&lt;/span&gt; &lt;span class="n"&gt;outputPath&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
    &lt;span class="n"&gt;writeFileText&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unpack&lt;/span&gt; &lt;span class="n"&gt;outputPath&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;

&lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="kt"&gt;ManageTextContent&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="n"&gt;capitalizeContent&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
  &lt;span class="n"&gt;capitalizeContent&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toUpper&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By using &lt;code&gt;optparse-applicative&lt;/code&gt;, here's the implementation of &lt;code&gt;parseCommand&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;parseCommand&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Parser&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt;
&lt;span class="n"&gt;parseCommand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;strOption&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;long&lt;/span&gt; &lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;short&lt;/span&gt; &lt;span class="sc"&gt;'i'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;metavar&lt;/span&gt; &lt;span class="s"&gt;"INPUT_FILE"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt; &lt;span class="s"&gt;"Input file"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;strOption&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;long&lt;/span&gt; &lt;span class="s"&gt;"output"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;short&lt;/span&gt; &lt;span class="sc"&gt;'o'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;metavar&lt;/span&gt; &lt;span class="s"&gt;"OUTPUT_FILE"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt; &lt;span class="s"&gt;"Output file"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;One obvious downside to this is the &lt;code&gt;n^2&lt;/code&gt; instance problem which Vasiliy Kevroletin mentions in his &lt;a href="https://serokell.io/blog/tagless-final"&gt;article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That's it! We import our library code to the &lt;code&gt;Main&lt;/code&gt; module and execute the program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Main&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;Relude&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;AppM&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;startApp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/thomashoneyman/purescript-halogen-realworld"&gt;Purescript Halogen Realworld repository&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.parsonsmatt.org/2018/03/22/three_layer_haskell_cake.html"&gt;Three Layer Cake by Matt Parson&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://serokell.io/blog/tagless-final"&gt;Introduction to Tagless Final by Vasiliy Kevroletin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jproyo.github.io/posts/2019-03-17-tagless-final-haskell.html"&gt;Tagles Final Encoding by Juan Pablo Royo Sales&lt;/a&gt;&lt;/p&gt;

</description>
      <category>haskell</category>
      <category>functional</category>
    </item>
    <item>
      <title>Haskell - Extracting IO</title>
      <dc:creator>Ken Aguilar</dc:creator>
      <pubDate>Thu, 30 Jul 2020 22:42:15 +0000</pubDate>
      <link>https://dev.to/piq9117/haskell-extracting-io-3op3</link>
      <guid>https://dev.to/piq9117/haskell-extracting-io-3op3</guid>
      <description>&lt;p&gt;There are more articles out there discussing this topic but this is my take on it. This topic can be long and complicated but I'll try and extract a section of it that we can focus on.&lt;/p&gt;

&lt;p&gt;Let's do a &lt;a href="https://taezos.org/piq9117/notes-examples/src/branch/master/abstracting-io"&gt;contrived example&lt;/a&gt;. Let's say we have a function that reads a file, processes it by capitalizing all the characters, then writes the results to another file. This is the first iteration of this function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="cp"&gt;{-# LANGUAGE OverloadedStrings #-}&lt;/span&gt;
&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Lib&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;Relude&lt;/span&gt;

&lt;span class="c1"&gt;-- text&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="k"&gt;qualified&lt;/span&gt; &lt;span class="nn"&gt;Data.Text&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;

&lt;span class="c1"&gt;-- 1. reads the file&lt;/span&gt;
&lt;span class="c1"&gt;-- 2. capitalizes all the characters&lt;/span&gt;
&lt;span class="c1"&gt;-- 3. writes result to the output path&lt;/span&gt;
&lt;span class="n"&gt;processFile&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;processFile&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;inputFile&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;readFileText&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt;
  &lt;span class="n"&gt;writeFileText&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toUpper&lt;/span&gt; &lt;span class="n"&gt;inputFile&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This adequately performs the task we want. The problem comes when we want to test the text processing without interacting with the file system. Sure, we can unit test the text processing it self but what if we want to see how the text processing behaves in the &lt;code&gt;processFile&lt;/code&gt; function? &lt;/p&gt;

&lt;p&gt;I learned mtl, tagless final encoding, and started reading about free monads, fused-effects, etc to be able to extract &lt;code&gt;IO&lt;/code&gt; out; among other things. Then, I totally ignored an easier technique. Which is to make the "side-effecty" functions into a parameter, and give it a basic type constraint of &lt;code&gt;Monad&lt;/code&gt; instead of &lt;code&gt;IO&lt;/code&gt;, like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;processFileBase&lt;/span&gt;
  &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Monad&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="kt"&gt;Text&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="kt"&gt;FilePath&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="nb"&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="kt"&gt;FilePath&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;processFileBase&lt;/span&gt; &lt;span class="n"&gt;readFileF&lt;/span&gt; &lt;span class="n"&gt;writeFileF&lt;/span&gt; &lt;span class="n"&gt;inputPath&lt;/span&gt; &lt;span class="n"&gt;outputPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;inputFile&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;readFileF&lt;/span&gt; &lt;span class="n"&gt;inputPath&lt;/span&gt;
  &lt;span class="n"&gt;writeFileF&lt;/span&gt; &lt;span class="n"&gt;outputPath&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toUpper&lt;/span&gt; &lt;span class="n"&gt;inputFile&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can use some type alias to make it less confusing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;ReadFileF&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
&lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;WriteFileF&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;processFileBase&lt;/span&gt;
  &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Monad&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;ReadFileF&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;WriteFileF&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We've extracted out the &lt;code&gt;IO&lt;/code&gt;. Yaaay! This function is now more flexible. We can pass in functions as long as they have a &lt;code&gt;Monad&lt;/code&gt; instance. If we go back to our &lt;code&gt;IO&lt;/code&gt; implementation we can provide it with functions from &lt;code&gt;relude&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;processFileWithIO&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;MonadIO&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;processFileWithIO&lt;/span&gt; &lt;span class="n"&gt;inputPath&lt;/span&gt; &lt;span class="n"&gt;outputPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;processFileBase&lt;/span&gt;
  &lt;span class="n"&gt;readFileText&lt;/span&gt;
  &lt;span class="n"&gt;writeFileText&lt;/span&gt;
  &lt;span class="n"&gt;inputPath&lt;/span&gt;
  &lt;span class="n"&gt;outputPath&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Another advantage of this technique is we can use another library and don't have to restructure our program. Let's say we ended up dropping &lt;code&gt;relude&lt;/code&gt; and using &lt;br&gt;
&lt;code&gt;prelude&lt;/code&gt; instead. We can massage the &lt;code&gt;writeFile&lt;/code&gt; and &lt;code&gt;readFile&lt;/code&gt; functions from &lt;code&gt;prelude&lt;/code&gt; so it can fit our program. Like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;
&lt;span class="n"&gt;readFilePrelude&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;MonadIO&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
&lt;span class="n"&gt;readFilePrelude&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;liftIO&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;fmap&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Prelude&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readFile&lt;/span&gt;

&lt;span class="n"&gt;writeFilePrelude&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;MonadIO&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;writeFilePrelude&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;liftIO&lt;/span&gt; 
  &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kt"&gt;Prelude&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writeFile&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unpack&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;processFileWithIO&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;MonadIO&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;processFileWithIO&lt;/span&gt; &lt;span class="n"&gt;inputPath&lt;/span&gt; &lt;span class="n"&gt;outputPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;processFileBase&lt;/span&gt;
  &lt;span class="n"&gt;readFilePrelude&lt;/span&gt;
  &lt;span class="n"&gt;writeFilePrelude&lt;/span&gt;
  &lt;span class="n"&gt;inputPath&lt;/span&gt;
  &lt;span class="n"&gt;outputPath&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In testing, we can provide it different functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="cp"&gt;{-# LANGUAGE OverloadedStrings #-}&lt;/span&gt;
&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ProcessFileSpec&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="k"&gt;qualified&lt;/span&gt; &lt;span class="nn"&gt;Data.HashMap.Strict&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;HS&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;Lib&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;Relude&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;Test.Hspec&lt;/span&gt;

&lt;span class="n"&gt;textFileToProcess&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
&lt;span class="n"&gt;textFileToProcess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="s"&gt;"Letting the cat out of the bag is a whole lot easier than putting it back in."&lt;/span&gt;

&lt;span class="n"&gt;spec&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Spec&lt;/span&gt;
&lt;span class="n"&gt;spec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s"&gt;"processFile"&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s"&gt;"will process the file and capitalize every character"&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;ioRef&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;newIORef&lt;/span&gt; &lt;span class="kt"&gt;HS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;
      &lt;span class="kr"&gt;let&lt;/span&gt;
        &lt;span class="n"&gt;outPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"sample-output.txt"&lt;/span&gt;

        &lt;span class="n"&gt;testReadFile&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Monad&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
        &lt;span class="n"&gt;testReadFile&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="n"&gt;textFileToProcess&lt;/span&gt;

        &lt;span class="n"&gt;testWriteFile&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;MonadIO&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;  &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;testWriteFile&lt;/span&gt; &lt;span class="n"&gt;outputPath&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;liftIO&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;
          &lt;span class="n"&gt;modifyIORef&lt;/span&gt; &lt;span class="n"&gt;ioRef&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;HS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt; &lt;span class="n"&gt;outputPath&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="n"&gt;processFileBase&lt;/span&gt; &lt;span class="n"&gt;testReadFile&lt;/span&gt; &lt;span class="n"&gt;testWriteFile&lt;/span&gt; &lt;span class="s"&gt;"input-path.txt"&lt;/span&gt; &lt;span class="n"&gt;outPath&lt;/span&gt;

      &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;readIORef&lt;/span&gt; &lt;span class="n"&gt;ioRef&lt;/span&gt;

      &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
        &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kt"&gt;HS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;singleton&lt;/span&gt; &lt;span class="n"&gt;outPath&lt;/span&gt;
            &lt;span class="s"&gt;"LETTING THE CAT OUT OF THE BAG IS A WHOLE LOT EASIER THAN PUTTING IT BACK IN."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here we're using &lt;code&gt;IORef&lt;/code&gt; but you can use &lt;code&gt;Map&lt;/code&gt;, &lt;code&gt;List&lt;/code&gt;, &lt;code&gt;StateT&lt;/code&gt;, &lt;code&gt;WriterT&lt;/code&gt;. It's totally up to you. Whatever suits your use-case.&lt;/p&gt;

&lt;p&gt;This technique can take you a long way! It is also a good complement to techniques like &lt;code&gt;mtl&lt;/code&gt; and tagless final encoding&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.parsonsmatt.org/2017/07/27/inverted_mocking.html"&gt;Invert Your Mocks! - Matt Parsons&lt;/a&gt;&lt;/p&gt;

</description>
      <category>functional</category>
      <category>haskell</category>
    </item>
    <item>
      <title>Typescript - Button Color State with ADTs </title>
      <dc:creator>Ken Aguilar</dc:creator>
      <pubDate>Tue, 23 Jun 2020 01:27:58 +0000</pubDate>
      <link>https://dev.to/piq9117/typescript-button-color-state-with-adts-1755</link>
      <guid>https://dev.to/piq9117/typescript-button-color-state-with-adts-1755</guid>
      <description>&lt;p&gt;I've seen enough typescript code that I can say that &lt;code&gt;booleans&lt;/code&gt; are over used. We need to normalize the use of sum types and reserve the use of &lt;code&gt;booleans&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are not a lot of things that &lt;code&gt;booleans&lt;/code&gt; can represent. Even something binary like the state of a light bulb can get confusing when it's represented with a &lt;code&gt;boolean&lt;/code&gt;. Should &lt;code&gt;True&lt;/code&gt; represent the light bulb being &lt;code&gt;off&lt;/code&gt; or &lt;code&gt;on&lt;/code&gt;, which one should &lt;code&gt;False&lt;/code&gt; represent? I'm sure with lots of comments it will be fine, but as we all know comments are not too effective in conveying information to other contributors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;toggleLightBulbState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;lightBulbState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// if the lightbulb is on return false to turn it off.&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;lightBulb&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&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="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 
  &lt;span class="c1"&gt;// otherwise turn on the light bulb.&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="kc"&gt;true&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;Imagine this withtout comments, would you able able to understand what this code is doing?&lt;/p&gt;

&lt;p&gt;Let's go through a contrived example and deal with button color states and fake http states, and eventually convert it to use sum types.&lt;/p&gt;

&lt;p&gt;We'll be using &lt;a href="https://bulma.io/documentation/"&gt;bulma&lt;/a&gt; css classes in the example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&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;react&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;colorToClassName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&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;string&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&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="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is-info&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="k"&gt;else&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;red&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="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is-danger&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="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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is-warning&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;return&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;colorToClassname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;color&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;Hello&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&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;The parent component&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;Button&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;./Button.tsx&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;responseToColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;string&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;response&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;successs&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="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&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="k"&gt;else&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;response&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;warning&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="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yellow&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="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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;red&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;httpResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;section&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;responseToColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;httpResponse&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;Equality checks with strings is definitely error prone but it looks like this is fine, especially for something small scale but imagine an actual application with so many more cases and so much more logic. Depending on booleans and string equality will be a source of great agony. What can help us here is the type checker! Even though typescript is not as strong as something like purescript or haskell it can still help a great deal.&lt;/p&gt;

&lt;p&gt;With purescript we can do something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- sum type representing all possible colors this button can render&lt;/span&gt;
&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;ButtonColor&lt;/span&gt;
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Blue&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;Red&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;Yellow&lt;/span&gt;

&lt;span class="c1"&gt;-- transforms ButtonColor to Bulma CSS classes.&lt;/span&gt;
&lt;span class="c1"&gt;-- Pattern match the colors and return the matching css class.&lt;/span&gt;
&lt;span class="c1"&gt;-- These bulma classes are not exposed outside this function.&lt;/span&gt;
&lt;span class="n"&gt;colorToClassName&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;ButtonColor&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="n"&gt;colorToClassName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
  &lt;span class="kt"&gt;Blue&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"is-info"&lt;/span&gt;
  &lt;span class="kt"&gt;Red&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"is-danger"&lt;/span&gt;
  &lt;span class="kt"&gt;Yellow&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"is-warning"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ButtonColor&lt;/code&gt; type that represents all the possible colors the button can render can then be exported so it can be used in the &lt;code&gt;colorToClassName&lt;/code&gt; function. With a fake http response, we can model it with a sum type and do a case match and transform that into our button colors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- type representing http response status.&lt;/span&gt;
&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Success&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;Error&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;Warning&lt;/span&gt;

&lt;span class="c1"&gt;-- transforms http response to button color.&lt;/span&gt;
&lt;span class="n"&gt;responseToColor&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;ButtonColor&lt;/span&gt;
&lt;span class="n"&gt;responseToColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
  &lt;span class="kt"&gt;Success&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Blue&lt;/span&gt;
  &lt;span class="kt"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Red&lt;/span&gt;
  &lt;span class="kt"&gt;Warning&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Yellow&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By using types, the purescript type checker can help us verify our program. I'm using "verify" loosely here, I don't mean formal verification.&lt;/p&gt;

&lt;p&gt;After that long tangent let's go back to typescript and see if we can recreate what we did in purescript, and let's do it in react! Let's start with the button component and model the possible color states of this button. For a detailed explanation on sum types in typescript, check out &lt;a href="https://dev.to/gcanti/functional-design-algebraic-data-types-36kf"&gt;Guilio Canti'sarticle&lt;/a&gt;. In typesript, sum types are called &lt;code&gt;discriminated unions&lt;/code&gt;. In order to determine which type is being matched in a pattern match it needs a &lt;code&gt;discriminant&lt;/code&gt;. We'll be using the &lt;code&gt;tag&lt;/code&gt; field as our &lt;code&gt;discriminant&lt;/code&gt;. This is used in our "poor man's" pattern matching, which is a &lt;code&gt;switch&lt;/code&gt; statement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&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;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Red&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;red&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Blue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Yellow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yellow&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ButtonColor&lt;/span&gt;
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Red&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Blue&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Yellow&lt;/span&gt;

&lt;span class="c1"&gt;// poor man's pattern matching.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toClassName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ButtonColor&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&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;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tag&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;blue&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is-info&lt;/span&gt;&lt;span class="dl"&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;red&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is-danger&lt;/span&gt;&lt;span class="dl"&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;yellow&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is-warning&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="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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Blue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&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;red&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Red&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;red&lt;/span&gt;&lt;span class="dl"&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;yellow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Yellow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yellow&lt;/span&gt;&lt;span class="dl"&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;function&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ButtonColor&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&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;button &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;toClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&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;Hello&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&amp;gt; &lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since I don't like using &lt;code&gt;switch&lt;/code&gt; statements, let's modify the code a little bit using the &lt;code&gt;Option&lt;/code&gt; type, specifically the utility function &lt;code&gt;fromNullalble&lt;/code&gt; and it will come from the library &lt;a href="https://github.com/gcanti/fp-ts"&gt;fp-ts&lt;/a&gt;. We'll also add the &lt;code&gt;className&lt;/code&gt; field to the interfaces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&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;react&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pipe&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;fp-ts/lib/function&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fromNullable&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;getOrElse&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;fp-ts/lib/Option&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Red&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Blue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt;  &lt;span class="nx"&gt;Yellow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yellow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;NoColor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noColor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;type&lt;/span&gt; &lt;span class="nx"&gt;ButtonColor&lt;/span&gt;
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Red&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Blue&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Yellow&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;NoColor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// implementation of the colors&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;blue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Blue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is-info&lt;/span&gt;&lt;span class="dl"&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;red&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Red&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is-danger&lt;/span&gt;&lt;span class="dl"&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;yellow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Yellow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yellow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is-warning&lt;/span&gt;&lt;span class="dl"&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;noColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NoColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noColor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Colors&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;red&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;yellow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Yellow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;noColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NoColor&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;colors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Colors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;red&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;yellow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;noColor&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;toClassName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ButtonColor&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;// pattern matching&lt;/span&gt;
  &lt;span class="c1"&gt;// This "pattern matching" works because they all have the className field.&lt;/span&gt;
  &lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;fromNullable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tag&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;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ButtonColor&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;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;getOrElse&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;noColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&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;function&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ButtonColor&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&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;button &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;toClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&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;Hello&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&amp;gt; &lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;fromNullable&lt;/code&gt; transforms it into an &lt;code&gt;Option&lt;/code&gt; type which is another sum type with &lt;code&gt;None&lt;/code&gt; and &lt;code&gt;Some&amp;lt;A&amp;gt;&lt;/code&gt; as its inhabitants. If we access a property that is not available in &lt;code&gt;colors&lt;/code&gt; it will go to the &lt;code&gt;getOrElse&lt;/code&gt; function and return &lt;code&gt;noColor&lt;/code&gt;, otherwise it will match a color then access the &lt;code&gt;className&lt;/code&gt; property. &lt;/p&gt;

&lt;p&gt;Now, let's look at the parent component and model the fake http response into something we can understand or something that makes sense in the context of the app, and transform that fake http response to a button color. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Success&lt;/code&gt;, &lt;code&gt;Error&lt;/code&gt;, and &lt;code&gt;Warning&lt;/code&gt; are the possible states for our fake http response here. They are then used in &lt;code&gt;Response&lt;/code&gt; to form a union of all possible states of a fake http response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.css&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;red&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;yellow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ButtonColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Blue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Yellow&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;./Button&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pipe&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;fp-ts/lib/function&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fromNullable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getOrElse&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fp-ts/lib/Option&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Success&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Warning&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;warning&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Yellow&lt;/span&gt;&lt;span class="p"&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;Response&lt;/span&gt;
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Success&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Warning&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Responses&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Warning&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;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;blue&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;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;red&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;warning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Warning&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;warning&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;yellow&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;responses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Responses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;success&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;span class="nx"&gt;warning&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;responseToColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ButtonColor&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;// pattern matching&lt;/span&gt;
  &lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;fromNullable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tag&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;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Response&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;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;getOrElse&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;red&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ButtonColor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// have to tell typescript red is a member of ButtonColor&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;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fakeHttpResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&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;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;section&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;responseToColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fakeHttpResponse&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;As a result we have eleminated &lt;code&gt;booleans&lt;/code&gt; in our tiny app and made the possible states of button colors and fake http response more explicit. We didn't have to figure out whether &lt;code&gt;True&lt;/code&gt; would mean "blue", "red", or "yellow". We didn't have to write long comments explaining how booleans would represent our fake http response.&lt;/p&gt;

&lt;h1&gt;
  
  
  Acknowledgements
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://dev.to/gcanti/functional-design-algebraic-data-types-36kf"&gt;Functional design: Algebraic Data Types - Guilio Canti&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/gcanti/fp-ts"&gt;fp-ts&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Repo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://taezos.org/piq9117/notes-examples/src/branch/master/button-sum-types"&gt;Button States&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>functional</category>
    </item>
    <item>
      <title>Nix - Trying out Haskell with less hassle</title>
      <dc:creator>Ken Aguilar</dc:creator>
      <pubDate>Wed, 10 Jun 2020 01:07:53 +0000</pubDate>
      <link>https://dev.to/piq9117/nix-trying-out-haskell-with-less-hassle-2if</link>
      <guid>https://dev.to/piq9117/nix-trying-out-haskell-with-less-hassle-2if</guid>
      <description>&lt;p&gt;I heard you want to try out haskell but like me you hesitate because you don't know how to setup your enviroment for Haskell. Okay, hear me out. Nix can be the solution, I know you have to learn more. However, it's not that much. At least that's what I see. Just learn a little bit of nix now and learn as you go!&lt;/p&gt;

&lt;p&gt;So if I convinced you to learn a little bit of nix. Go ahead and download it from their &lt;a href="https://nixos.org/download.html"&gt;website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, instead of worrying what system configuration you have to do, you just do this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-project
nix-shell &lt;span class="nt"&gt;--pure&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ghc cabal-install &lt;span class="nt"&gt;--run&lt;/span&gt; &lt;span class="s2"&gt;"cabal init"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What's happening here is you're telling nix to go get &lt;code&gt;ghc&lt;/code&gt;(compiler) and &lt;code&gt;cabal-install&lt;/code&gt;(build tool), and run the command &lt;code&gt;cabal init&lt;/code&gt;. This will generate a very small scaffold for a haskell project. Since we used the flag &lt;code&gt;--pure&lt;/code&gt; it won't install anything global in your system.&lt;/p&gt;

&lt;p&gt;Your &lt;code&gt;my-project&lt;/code&gt; directory should look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;my-project
|-- CHANGELOG.md
|-- Main.hs
|-- my-project.cabal
|-- Setup.hs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Main.hs&lt;/code&gt; should contain the &lt;code&gt;Hello World&lt;/code&gt; program. This is also where you want to write your experiment haskell code.&lt;/p&gt;

&lt;p&gt;Since you used &lt;code&gt;ghc&lt;/code&gt; and &lt;code&gt;cabal&lt;/code&gt; in a pure environment you won't find them when you try to execute &lt;code&gt;cabal&lt;/code&gt; in the console. So you won't be able to run this project as is. What you can do is play with your haskell&lt;br&gt;
project in a &lt;code&gt;nix-shell&lt;/code&gt;. You can do this by first generating a &lt;code&gt;default.nix&lt;/code&gt; file. This can be done by doing this command in your project directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;nix-shell &lt;span class="nt"&gt;--pure&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; cabal2nix &lt;span class="nt"&gt;--run&lt;/span&gt; &lt;span class="s2"&gt;"cabal2nix ."&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; default.nix
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will generate the &lt;code&gt;default.nix&lt;/code&gt; file and will contain&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight nix"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;mkDerivation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;stdenv&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt;
&lt;span class="nv"&gt;mkDerivation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;pname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-project"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nv"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0.1.0.0"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nv"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;./.&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nv"&gt;isLibrary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nv"&gt;isExecutable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nv"&gt;executableHaskellDepends&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;base&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="nv"&gt;license&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"unknown"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nv"&gt;hydraPlatforms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;stdenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;platforms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;none&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;This file describes your project. It's like a function that takes in nix stuff.&lt;/p&gt;

&lt;p&gt;For the last part, write the &lt;code&gt;shell.nix&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt; nixpkgs ? import &amp;lt;nixpkgs&amp;gt; &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;:

&lt;span class="nb"&gt;let
  &lt;/span&gt;inherit &lt;span class="o"&gt;(&lt;/span&gt;nixpkgs&lt;span class="o"&gt;)&lt;/span&gt; pkgs&lt;span class="p"&gt;;&lt;/span&gt;
  inherit &lt;span class="o"&gt;(&lt;/span&gt;pkgs&lt;span class="o"&gt;)&lt;/span&gt; haskellPackages&lt;span class="p"&gt;;&lt;/span&gt;

  project &lt;span class="o"&gt;=&lt;/span&gt; haskellPackages.callPackage ./default.nix &lt;span class="o"&gt;{}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;in
&lt;/span&gt;pkgs.stdenv.mkDerivation &lt;span class="o"&gt;{&lt;/span&gt;
  name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-project"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  buildInputs &lt;span class="o"&gt;=&lt;/span&gt; project.env.nativeBuildInputs ++ &lt;span class="o"&gt;[&lt;/span&gt;
    haskellPackages.cabal-install
  &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When you perform &lt;code&gt;nix-shell --pure&lt;/code&gt; in your project directory. It will go into a nix environment and you'll see your command prompt turn like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;nix-shell:~/my-project]&lt;span class="err"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this environment you'll have access to &lt;code&gt;cabal&lt;/code&gt;. So you can build and run your project with &lt;code&gt;cabal new build&lt;/code&gt; and &lt;code&gt;cabal new-run&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you want to expirement with a haskell package from &lt;a href="https://hackage.haskell.org/"&gt;hackage&lt;/a&gt; like the &lt;code&gt;text&lt;/code&gt; package, you can add it to your &lt;code&gt;my-project.cabal&lt;/code&gt; file, in the &lt;code&gt;build-depends&lt;/code&gt; section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;cabal-version:       &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;1.10
&lt;span class="nt"&gt;--&lt;/span&gt; Initial package description &lt;span class="s1"&gt;'my-project.cabal'&lt;/span&gt; generated by &lt;span class="s1"&gt;'cabal
-- init'&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;  For further documentation, see
&lt;span class="nt"&gt;--&lt;/span&gt; http://haskell.org/cabal/users-guide/

name:                my-project
version:             0.1.0.0
&lt;span class="nt"&gt;--&lt;/span&gt; synopsis:
&lt;span class="nt"&gt;--&lt;/span&gt; description:
&lt;span class="nt"&gt;--&lt;/span&gt; bug-reports:
&lt;span class="nt"&gt;--&lt;/span&gt; license:
license-file:        LICENSE
&lt;span class="nt"&gt;--&lt;/span&gt; author:
&lt;span class="nt"&gt;--&lt;/span&gt; maintainer:
&lt;span class="nt"&gt;--&lt;/span&gt; copyright:
&lt;span class="nt"&gt;--&lt;/span&gt; category:
build-type:          Simple
extra-source-files:  CHANGELOG.md

executable my-project
  main-is:             Main.hs
  &lt;span class="nt"&gt;--&lt;/span&gt; other-modules:
  &lt;span class="nt"&gt;--&lt;/span&gt; other-extensions:
  build-depends:       base &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;4.13 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &amp;lt;4.14
                     , text
  &lt;span class="nt"&gt;--&lt;/span&gt; hs-source-dirs:
  default-language:    Haskell2010
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You should also add this to your &lt;code&gt;default.nix&lt;/code&gt; file, so later on when you do decide to build your project with &lt;code&gt;nix-build&lt;/code&gt; you don't have to chase around packages. I'll probably cover &lt;code&gt;nix-build&lt;/code&gt; in another post.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt; mkDerivation, base, stdenv, text &lt;span class="o"&gt;}&lt;/span&gt;:
mkDerivation &lt;span class="o"&gt;{&lt;/span&gt;
  pname &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-project"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  version &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0.1.0.0"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  src &lt;span class="o"&gt;=&lt;/span&gt; ./.&lt;span class="p"&gt;;&lt;/span&gt;
  isLibrary &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  isExecutable &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  executableHaskellDepends &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; base text &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  license &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"unknown"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  hydraPlatforms &lt;span class="o"&gt;=&lt;/span&gt; stdenv.lib.platforms.none&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://maybevoid.com/posts/2019-01-27-getting-started-haskell-nix.html"&gt;Getting Started Haskell Project with Nix - Soares Chen&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/justinwoo/nix-shorts"&gt;Nix Shorts - Justin Woo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nix</category>
      <category>haskell</category>
      <category>functional</category>
    </item>
    <item>
      <title>Haskell - Generating lenses for third party libraries</title>
      <dc:creator>Ken Aguilar</dc:creator>
      <pubDate>Tue, 09 Jun 2020 21:14:29 +0000</pubDate>
      <link>https://dev.to/piq9117/haskell-generating-lenses-for-third-party-libraries-1oik</link>
      <guid>https://dev.to/piq9117/haskell-generating-lenses-for-third-party-libraries-1oik</guid>
      <description>&lt;p&gt;This is going to be a short post, maybe even a tweet size post. I'm going to highlight how to generate lenses for third party libraries because when I was searching for this information it wasn't that easy to find. &lt;/p&gt;

&lt;p&gt;My concern was less on the mechanics on how to generate them but more on best practices, I wasn't sure if generating lenses for data types I don't own is a good practice. When I asked in &lt;a href="https://fpchat-invite.herokuapp.com/"&gt;fp-chat&lt;/a&gt;, I was told to "Go hog wild!" and didn't get any opposing views. So that gave me the peace of mind to do this.&lt;/p&gt;

&lt;p&gt;I'm going to use the &lt;a href="https://hackage.haskell.org/package/purescript-0.13.8/docs/Language-PureScript-CST-Types.html"&gt;purescript language library&lt;/a&gt; as an example since it's the most recent library I had to work with when I was working with my project, &lt;a href="https://taezos.org/taezos/umu-halogen"&gt;umu-halogen&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'm going to use &lt;code&gt;makeLenses&lt;/code&gt; from &lt;code&gt;Control.Lens.TH&lt;/code&gt;. The default configuration of &lt;code&gt;makeLenses&lt;/code&gt; is it will only generate lenses for record fields that are prefixed with an underscore.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;Person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Person&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;firstName&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="c1"&gt;-- does not generate lens for this field.&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_lastName&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="c1"&gt;-- generates the lens for this field.&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Show&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;makeLenses&lt;/span&gt; &lt;span class="n"&gt;''Person&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Before I can start generating lenses for the types I don't own, I have to change the &lt;code&gt;makeLenses&lt;/code&gt; configuration a little bit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Util&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;Language.Haskell.TH&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;Control.Lens.Operators&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;Control.Lens.TH&lt;/span&gt;

&lt;span class="n"&gt;mkCustomLenses&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;DecsQ&lt;/span&gt;
&lt;span class="n"&gt;mkCustomLenses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;makeLensesWith&lt;/span&gt;
  &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;lensRules&lt;/span&gt;
  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;lensField&lt;/span&gt;
  &lt;span class="o"&gt;.~&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;TopName&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;mkName&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;nameBase&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="s"&gt;"L"&lt;/span&gt; &lt;span class="p"&gt;)])&lt;/span&gt; &lt;span class="c1"&gt;-- you can append whatever suits your code base here, I chose to append "L"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It has to be in a separate module from where you generate the lenses because the compiler will complain with this error&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;GHC stage restriction:
      &lt;span class="sb"&gt;`&lt;/span&gt;mkCustomLenses&lt;span class="s1"&gt;' is used in a top-level splice, quasi-quote, or annotation,
      and must be imported, not defined locally
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After that setup you can start generating lenses!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Optics&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="c1"&gt;-- util&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;Util&lt;/span&gt;

&lt;span class="c1"&gt;-- purescript&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;           &lt;span class="nn"&gt;Language.PureScript.CST.Types&lt;/span&gt;

&lt;span class="n"&gt;makePrisms&lt;/span&gt; &lt;span class="n"&gt;''Declaration&lt;/span&gt;
&lt;span class="n"&gt;makePrisms&lt;/span&gt; &lt;span class="n"&gt;''Guarded&lt;/span&gt;
&lt;span class="n"&gt;makePrisms&lt;/span&gt; &lt;span class="n"&gt;''Expr&lt;/span&gt;

&lt;span class="n"&gt;mkCustomLenses&lt;/span&gt; &lt;span class="n"&gt;''ValueBindingFields&lt;/span&gt;
&lt;span class="n"&gt;mkCustomLenses&lt;/span&gt; &lt;span class="n"&gt;''Name&lt;/span&gt;
&lt;span class="n"&gt;mkCustomLenses&lt;/span&gt; &lt;span class="n"&gt;''Ident&lt;/span&gt;
&lt;span class="n"&gt;mkCustomLenses&lt;/span&gt; &lt;span class="n"&gt;''Labeled&lt;/span&gt;
&lt;span class="n"&gt;mkCustomLenses&lt;/span&gt; &lt;span class="n"&gt;''Where&lt;/span&gt;
&lt;span class="n"&gt;mkCustomLenses&lt;/span&gt; &lt;span class="n"&gt;''Wrapped&lt;/span&gt;
&lt;span class="n"&gt;mkCustomLenses&lt;/span&gt; &lt;span class="n"&gt;''Separated&lt;/span&gt;
&lt;span class="n"&gt;mkCustomLenses&lt;/span&gt; &lt;span class="n"&gt;''Module&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, if I want to manipulate &lt;code&gt;Separated&lt;/code&gt; I can do something like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;updateToEmptyList&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Separated&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Separated&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;updateToEmptyList&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;sepTailL&lt;/span&gt; &lt;span class="o"&gt;.~&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When it comes to sum types you can just use &lt;code&gt;makePrisms&lt;/code&gt; to generate prisms.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://leanpub.com/optics-by-example"&gt;Optics by Example - Chris Penner&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hackage.haskell.org/package/lens-tutorial-1.0.4/docs/Control-Lens-Tutorial.html"&gt;Lens Tutorial&lt;/a&gt;&lt;/p&gt;

</description>
      <category>haskell</category>
      <category>lenses</category>
      <category>functional</category>
    </item>
    <item>
      <title>Haskell - Boolean Blindness == True</title>
      <dc:creator>Ken Aguilar</dc:creator>
      <pubDate>Thu, 16 Apr 2020 09:02:53 +0000</pubDate>
      <link>https://dev.to/piq9117/haskell-boolean-blindness-true-2820</link>
      <guid>https://dev.to/piq9117/haskell-boolean-blindness-true-2820</guid>
      <description>&lt;p&gt;What does the title even mean? &lt;code&gt;True&lt;/code&gt;? for what? Good? Bad? Useful? If it was &lt;code&gt;False&lt;/code&gt;, would we see any meaning?&lt;/p&gt;

&lt;p&gt;Even the state of a light bulb cannot be properly represented by booleans. Would &lt;code&gt;True&lt;/code&gt; mean the light is on? or would it mean off?&lt;/p&gt;

&lt;p&gt;What if the decision on whether Boolean Blindess is bad or good is represented with a sum type&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;Decision&lt;/span&gt; 
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Bad&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;Good&lt;/span&gt;
  &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="kt"&gt;Show&lt;/span&gt;

&lt;span class="n"&gt;makeDecision&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Decision&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
&lt;span class="n"&gt;makeDecision&lt;/span&gt; &lt;span class="n"&gt;decision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;decision&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
  &lt;span class="kt"&gt;Bad&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Boolean blindness is "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="kt"&gt;Bad&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"!"&lt;/span&gt;
  &lt;span class="kt"&gt;Good&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Boolean blindess is "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="kt"&gt;Good&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I think using the sum type gives it meaning. Now we can make a decision about Boolean Blindess.&lt;/p&gt;

&lt;p&gt;I lessen confusion in my code by using booleans conservatively.&lt;/p&gt;

</description>
      <category>haskell</category>
    </item>
    <item>
      <title>Purescript - Halogen Routing</title>
      <dc:creator>Ken Aguilar</dc:creator>
      <pubDate>Sun, 29 Mar 2020 00:45:37 +0000</pubDate>
      <link>https://dev.to/piq9117/purescript-halogen-routing-2kfg</link>
      <guid>https://dev.to/piq9117/purescript-halogen-routing-2kfg</guid>
      <description>&lt;p&gt;This entry will be pretty similar to my previous purescript-react-basic-hooks routing entry. Where I go over how routing works within the framework. This time it will be be using the halogen UI framework.&lt;/p&gt;

&lt;p&gt;Thanks to the &lt;a href="https://github.com/thomashoneyman/purescript-halogen-realworld"&gt;halogen realworld example&lt;/a&gt; it was easy to figure out how to do routing in halogen. &lt;/p&gt;

&lt;p&gt;Here's my understanding of it. I'll and try and extract the routing part of the example and focus on that in this entry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Router
&lt;/h2&gt;

&lt;p&gt;First off, the router component. This component is the parent component. It's the component that will decide what to render based on the route that's being queried to it. The &lt;code&gt;render&lt;/code&gt; function &lt;code&gt;case&lt;/code&gt; matches on the &lt;code&gt;Route&lt;/code&gt; then renders the component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Component.Router&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Prelude&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Data.Maybe&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;fromMaybe&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Data.Either&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;hush&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Internal Page&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Page.Home&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Home&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Page.About&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;About&lt;/span&gt;
&lt;span class="c1"&gt;-- Internal Service&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Service.Route&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Service.Navigate&lt;/span&gt;
&lt;span class="c1"&gt;-- Web&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Web.Event.Event&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;preventDefault&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Web.UIEvent.MouseEvent&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;toEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;MouseEvent&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Effect&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Effect.Class&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;MonadEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;liftEffect&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Routing&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Duplex&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Hash&lt;/span&gt;
&lt;span class="c1"&gt;-- Halogen&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Halogen&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;H&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Halogen.HTML&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;HH&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Halogen.HTML.Properties&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;HP&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Halogen.HTML.Events&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;HE&lt;/span&gt;

&lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;State&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;Query&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Navigate&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;

&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;Action&lt;/span&gt;
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Initialize&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;GoTo&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt; &lt;span class="kt"&gt;MouseEvent&lt;/span&gt;

&lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;ChildSlots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;home&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Home&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Slot&lt;/span&gt; &lt;span class="kt"&gt;Unit&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;about&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;About&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Slot&lt;/span&gt; &lt;span class="kt"&gt;Unit&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;component&lt;/span&gt;
  &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;MonadEffect&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Navigate&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;H&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Component&lt;/span&gt; &lt;span class="kt"&gt;HH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;HTML&lt;/span&gt; &lt;span class="kt"&gt;Query&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
&lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kt"&gt;H&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkComponent&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;initialState&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Nothing&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eval&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;H&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkEval&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kt"&gt;H&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;defaultEval&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;handleAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handleAction&lt;/span&gt;
    &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handleQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handleQuery&lt;/span&gt;
    &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initialize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="kt"&gt;Initialize&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;-- Renders a page component depending on which route is matched.&lt;/span&gt;
&lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;State&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;H&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;ComponentHTML&lt;/span&gt; &lt;span class="kt"&gt;Action&lt;/span&gt; &lt;span class="kt"&gt;ChildSlots&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
&lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;navbar&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
  &lt;span class="kt"&gt;Nothing&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;HH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;h1_&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;HH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="s"&gt;"Oh no! That page wasn't found"&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
    &lt;span class="kt"&gt;Home&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;HH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slot&lt;/span&gt; &lt;span class="kt"&gt;Home&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_home&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt; &lt;span class="kt"&gt;Home&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt; &lt;span class="n"&gt;absurd&lt;/span&gt;
    &lt;span class="kt"&gt;About&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;HH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slot&lt;/span&gt; &lt;span class="kt"&gt;About&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_about&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt; &lt;span class="kt"&gt;About&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt; &lt;span class="n"&gt;absurd&lt;/span&gt;

&lt;span class="n"&gt;handleAction&lt;/span&gt;
  &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;MonadEffect&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Navigate&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Action&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;H&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;HalogenM&lt;/span&gt; &lt;span class="kt"&gt;State&lt;/span&gt; &lt;span class="kt"&gt;Action&lt;/span&gt; &lt;span class="kt"&gt;ChildSlots&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="kt"&gt;Unit&lt;/span&gt;
&lt;span class="n"&gt;handleAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
  &lt;span class="c1"&gt;-- Handles initialization of the route&lt;/span&gt;
  &lt;span class="kt"&gt;Initialize&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;initialRoute&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;hush&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;parse&lt;/span&gt; &lt;span class="n"&gt;routeCodec&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;H&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;liftEffect&lt;/span&gt; &lt;span class="n"&gt;getHash&lt;/span&gt;
    &lt;span class="n"&gt;navigate&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;fromMaybe&lt;/span&gt; &lt;span class="kt"&gt;Home&lt;/span&gt; &lt;span class="n"&gt;initialRoute&lt;/span&gt;
  &lt;span class="c1"&gt;--  Handles the consecutive route changes.&lt;/span&gt;
  &lt;span class="kt"&gt;GoTo&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;liftEffect&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;preventDefault&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;toEvent&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;mRoute&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kt"&gt;H&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gets&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;
    &lt;span class="n"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;mRoute&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;navigate&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt;

&lt;span class="n"&gt;handleQuery&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;Query&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;H&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;HalogenM&lt;/span&gt; &lt;span class="kt"&gt;State&lt;/span&gt; &lt;span class="kt"&gt;Action&lt;/span&gt; &lt;span class="kt"&gt;ChildSlots&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;handleQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
  &lt;span class="c1"&gt;-- This is the case that runs every time the brower's hash route changes.&lt;/span&gt;
  &lt;span class="kt"&gt;Navigate&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;mRoute&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kt"&gt;H&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gets&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;
    &lt;span class="n"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;mRoute&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;
      &lt;span class="kt"&gt;H&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;modify_&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;navbar&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;HH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;HTML&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="kt"&gt;Action&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;HH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;HTML&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="kt"&gt;Action&lt;/span&gt;
&lt;span class="n"&gt;navbar&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kt"&gt;HH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;div_&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;HH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ul_&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;HH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;li_&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;HH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;HP&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;href&lt;/span&gt; &lt;span class="s"&gt;"#"&lt;/span&gt;
        &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;HE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="kt"&gt;GoTo&lt;/span&gt; &lt;span class="kt"&gt;Home&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="kt"&gt;HH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="s"&gt;"Home"&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="kt"&gt;HH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;li_&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;HH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;HP&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;href&lt;/span&gt; &lt;span class="s"&gt;"#"&lt;/span&gt;
        &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;HE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="kt"&gt;GoTo&lt;/span&gt; &lt;span class="kt"&gt;About&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="kt"&gt;HH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="s"&gt;"About"&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="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Page
&lt;/h2&gt;

&lt;p&gt;This is how these &lt;a href="https://www.taezos.org/piq9117/notes-examples/src/branch/master/halogen-routing/src/Page"&gt;pages&lt;/a&gt; are defined. These components will render the text &lt;strong&gt;Home&lt;/strong&gt; and &lt;strong&gt;About&lt;/strong&gt;. In a non-trivial application, these components will hold several components to form a "page", but for simplicity I left them off to just render text inside an &lt;code&gt;h1&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Route
&lt;/h2&gt;

&lt;p&gt;The key thing here is the &lt;code&gt;Route&lt;/code&gt; sum type. These are all the&lt;br&gt;
possible routes in the application. The rest of the code is for&lt;br&gt;
&lt;a href="https://github.com/natefaubion/purescript-routing-duplex"&gt;routing-duplex&lt;/a&gt; to help me encode and decode the routes. The routes can be directly written as strings but I prefer the safety of types. Plus, the string definition only stays here. So this lessens the fishing later on &lt;strong&gt;if ever there is&lt;/strong&gt; a bug in the routing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Service.Route&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Prelude&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Data.Generic.Rep&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Generic&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Data.Generic.Rep.Show&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;genericShow&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Routing&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Duplex&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;RouteDuplex&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;root&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Duplex.Generic&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;noArgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Duplex.Generic.Syntax&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;-- All possible routes in the application&lt;/span&gt;
&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt;
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Home&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;About&lt;/span&gt;

&lt;span class="n"&gt;derive&lt;/span&gt; &lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;genericRoute&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Generic&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt;
&lt;span class="n"&gt;derive&lt;/span&gt; &lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;eqRoute&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Eq&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt;
&lt;span class="n"&gt;derive&lt;/span&gt; &lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;ordRoute&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Ord&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt;

&lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;showRoute&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Show&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genericShow&lt;/span&gt;

&lt;span class="n"&gt;routeCodec&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;RouteDuplex'&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt;
&lt;span class="n"&gt;routeCodec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Home"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;noArgs&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"About"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"about"&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;noArgs&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Navigation
&lt;/h2&gt;

&lt;p&gt;Navigation capbility of this app is defined in a type class. This technique is known as &lt;a href="https://jproyo.github.io/posts/2019-03-17-tagless-final-haskell.html"&gt;tagless-final-encoding&lt;/a&gt;. It's a technique where we define a capability or method without concrete implementations and only a small set of requirements. In this case, the minimum requirement is it needs to be a &lt;code&gt;Monad&lt;/code&gt;. Then, an instance for &lt;code&gt;HalogenM&lt;/code&gt; is defined here to save us from calling &lt;code&gt;lift&lt;/code&gt;everywhere inside the action (e.g &lt;code&gt;lift $ navigate Home&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Service.Navigate&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Prelude&lt;/span&gt;

&lt;span class="c1"&gt;-- Internal Route&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Service.Route&lt;/span&gt;
&lt;span class="c1"&gt;-- Halogen&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Halogen&lt;/span&gt;

&lt;span class="kr"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Monad&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="kt"&gt;Navigate&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="n"&gt;navigate&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="kt"&gt;Unit&lt;/span&gt;

&lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;navigateHalogenM&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Navigate&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Navigate&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;HalogenM&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="n"&gt;slots&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="n"&gt;navigate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lift&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;navigate&lt;/span&gt;

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



&lt;h2&gt;
  
  
  AppM
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;AppM&lt;/code&gt; is a custom application monad that will provide concrete implementation for the capabilities, in this case it will only implement &lt;code&gt;Navigation&lt;/code&gt;. As you'll notice this only provides a natural transformation from &lt;code&gt;AppM&lt;/code&gt; to &lt;code&gt;Aff&lt;/code&gt;. In a typical application this will wrap the &lt;a href="https://www.fpcomplete.com/blog/2017/06/readert-design-pattern"&gt;ReaderT pattern&lt;/a&gt;. This is also the technique used in the [halogen real world example][halogen realworld]. I learned about this pattern &lt;a href="https://www.parsonsmatt.org/2018/03/22/three_layer_haskell_cake.html"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;AppM&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Prelude&lt;/span&gt;
&lt;span class="c1"&gt;-- Internal Service&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Service.Navigate&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Service.Route&lt;/span&gt;
&lt;span class="c1"&gt;-- Effect&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Effect.Class&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;MonadEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;liftEffect&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Aff&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Effect.Aff&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Aff&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Effect.Aff.Class&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;MonadAff&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Routing&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Hash&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;setHash&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Duplex&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Aff&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;runAppM&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="o"&gt;~&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Aff&lt;/span&gt;
&lt;span class="n"&gt;runAppM&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;

&lt;span class="n"&gt;derive&lt;/span&gt; &lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;functorAppM&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Functor&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt;
&lt;span class="n"&gt;derive&lt;/span&gt; &lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;applyAppM&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Apply&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt;
&lt;span class="n"&gt;derive&lt;/span&gt; &lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;applicativeAppM&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Applicative&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt;
&lt;span class="n"&gt;derive&lt;/span&gt; &lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;bindAppM&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Bind&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt;
&lt;span class="n"&gt;derive&lt;/span&gt; &lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;monadAppM&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Monad&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt;
&lt;span class="n"&gt;derive&lt;/span&gt; &lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;monadEffectAppM&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;MonadEffect&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt;
&lt;span class="n"&gt;derive&lt;/span&gt; &lt;span class="kr"&gt;newtype&lt;/span&gt; &lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;monadAffAppM&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;MonadAff&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt;

&lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;navigateAppM&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Navigate&lt;/span&gt; &lt;span class="kt"&gt;AppM&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="n"&gt;navigate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;liftEffect&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;setHash&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="n"&gt;routeCodec&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Main
&lt;/h2&gt;

&lt;p&gt;Finally, the &lt;code&gt;Main&lt;/code&gt; module. This is where the application is ran. This is also the place where the browser's route is observed. Whenever the route changes the callback of &lt;code&gt;matchesWith&lt;/code&gt; will be called. This callback will query the router component with &lt;code&gt;Navigate&lt;/code&gt; passing the &lt;code&gt;new&lt;/code&gt; route.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Main&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Prelude&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Data.Maybe&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&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;-- Internal&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;AppM&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;runAppM&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Internal Components&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Component.Router&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Router&lt;/span&gt;
&lt;span class="c1"&gt;-- Internal Service&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Service.Route&lt;/span&gt;
&lt;span class="c1"&gt;-- Effect&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Effect.Class&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;liftEffect&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Aff&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Effect.Aff&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Aff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;launchAff_&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Routing&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Duplex&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Hash&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;matchesWith&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Halogen&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Halogen&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;H&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Halogen.HTML&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;HH&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Halogen.Aff&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;HA&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Halogen.VDom.Driver&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;runUI&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Effect&lt;/span&gt; &lt;span class="kt"&gt;Unit&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;HA&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runHalogenAff&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kt"&gt;HA&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;awaitBody&lt;/span&gt;
  &lt;span class="kr"&gt;let&lt;/span&gt;
    &lt;span class="n"&gt;rootComponent&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;H&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Component&lt;/span&gt; &lt;span class="kt"&gt;HH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;HTML&lt;/span&gt; &lt;span class="kt"&gt;Router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Query&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="kt"&gt;Void&lt;/span&gt; &lt;span class="kt"&gt;Aff&lt;/span&gt;
    &lt;span class="n"&gt;rootComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;H&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hoist&lt;/span&gt; &lt;span class="n"&gt;runAppM&lt;/span&gt; &lt;span class="kt"&gt;Router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt;

  &lt;span class="c1"&gt;-- Run the application&lt;/span&gt;
  &lt;span class="n"&gt;halogenIO&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;runUI&lt;/span&gt; &lt;span class="n"&gt;rootComponent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;

  &lt;span class="c1"&gt;-- Listen to the route changes.&lt;/span&gt;
  &lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;liftEffect&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;matchesWith&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;parse&lt;/span&gt; &lt;span class="n"&gt;routeCodec&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;mOld&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;mOld&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;launchAff_&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;halogenIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kt"&gt;H&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tell&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kt"&gt;Router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Navigate&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;
  &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/thomashoneyman/purescript-halogen-realworld"&gt;Purescript Halogen Realworld Example&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jproyo.github.io/posts/2019-03-17-tagless-final-haskell.html"&gt;Tagless Final Encoding&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.fpcomplete.com/blog/2017/06/readert-design-pattern"&gt;ReaderT Design Pattern&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.parsonsmatt.org/2018/03/22/three_layer_haskell_cake.html"&gt;Three Layer Haskell Cake&lt;/a&gt;&lt;/p&gt;

</description>
      <category>purescript</category>
      <category>halogen</category>
      <category>routing</category>
    </item>
    <item>
      <title>Purescript - React Basic Hooks Routing</title>
      <dc:creator>Ken Aguilar</dc:creator>
      <pubDate>Fri, 27 Mar 2020 03:32:07 +0000</pubDate>
      <link>https://dev.to/piq9117/purescript-react-basic-hooks-routing-4a88</link>
      <guid>https://dev.to/piq9117/purescript-react-basic-hooks-routing-4a88</guid>
      <description>&lt;p&gt;When I started doing web applications with purescript react and halogen I had no clue how to do things. One of those things is routing. It wasn't that hard for halogen because of the &lt;a href="https://github.com/thomashoneyman/purescript-halogen-realworld"&gt;realworld example&lt;/a&gt;. It's built ready for production. It even has great documentation!&lt;/p&gt;

&lt;p&gt;Unfortunately, when it came to &lt;a href="https://pursuit.purescript.org/packages/purescript-react-basic-hooks/4.2.2"&gt;react-basic-hooks&lt;/a&gt; this information wasn't readily available. So here's my take on routing with react-basic/react-basic-hooks.&lt;/p&gt;

&lt;p&gt;The router component is the parent of all the components. The router component will decide which component to render depending on the &lt;code&gt;Route&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Router
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Component.Router&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Prelude&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Data.Either&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;hush&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Data.Maybe&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;fromMaybe&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Internal Page&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Page.Home&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Home&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Page.About&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;About&lt;/span&gt;
&lt;span class="c1"&gt;-- Internal Service&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Service.Route&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Service.Navigate&lt;/span&gt;
&lt;span class="c1"&gt;-- Internal Component&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Component.Store&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;mkRouteStore&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Effect&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Routing&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Duplex&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Hash&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;getHash&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- React&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;React.Basic.Hooks&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;ReactComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;ReactContext&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;React.Basic.Hooks&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;React&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;React.Basic.DOM&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;RD&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;React.Basic.Events&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;RE&lt;/span&gt;

&lt;span class="n"&gt;mkComponent&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;ReactComponent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;mkComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;-- Grab initial route. &lt;/span&gt;
  &lt;span class="c1"&gt;-- This will try to match the browser's hash route. &lt;/span&gt;
  &lt;span class="n"&gt;mInitialRoute&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;hush&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;parse&lt;/span&gt; &lt;span class="n"&gt;routeCodec&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getHash&lt;/span&gt;
  &lt;span class="c1"&gt;-- If it doesn't find a match it will default to the home route.&lt;/span&gt;
  &lt;span class="c1"&gt;-- Then a context is created on that route.&lt;/span&gt;
  &lt;span class="n"&gt;routeContext&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;createContext&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;fromMaybe&lt;/span&gt; &lt;span class="kt"&gt;Home&lt;/span&gt; &lt;span class="n"&gt;mInitialRoute&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;mkRouteStore&lt;/span&gt; &lt;span class="n"&gt;routeContext&lt;/span&gt;
  &lt;span class="n"&gt;nav&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;mkRouter&lt;/span&gt; &lt;span class="n"&gt;routeContext&lt;/span&gt;
  &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="s"&gt;"RouterContainer"&lt;/span&gt; &lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="n"&gt;nav&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;]}&lt;/span&gt;

&lt;span class="c1"&gt;-- This is the function that will match Route and render the right element that&lt;/span&gt;
&lt;span class="c1"&gt;-- matches that route.&lt;/span&gt;
&lt;span class="n"&gt;mkRouter&lt;/span&gt;
  &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;ReactContext&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;ReactComponent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;mkRouter&lt;/span&gt; &lt;span class="n"&gt;routeContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;home&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kt"&gt;Home&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkComponent&lt;/span&gt;
  &lt;span class="n"&gt;about&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kt"&gt;About&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkComponent&lt;/span&gt;
  &lt;span class="n"&gt;navbar&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;mkNavbar&lt;/span&gt;
  &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="s"&gt;"Router"&lt;/span&gt; &lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;useContext&lt;/span&gt; &lt;span class="n"&gt;routeContext&lt;/span&gt;
    &lt;span class="n"&gt;pure&lt;/span&gt;
      &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fragment&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="n"&gt;navbar&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
             &lt;span class="kt"&gt;Home&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="n"&gt;home&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
             &lt;span class="kt"&gt;About&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="n"&gt;about&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;mkNavbar&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;ReactComponent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;mkNavbar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="s"&gt;"Navbar"&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;pure&lt;/span&gt;
      &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kt"&gt;RD&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nav&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
          &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;RD&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;RD&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="s"&gt;"Home"&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;RE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handler_&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;navigate&lt;/span&gt; &lt;span class="kt"&gt;Home&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;RD&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;RD&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="s"&gt;"About"&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;RE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handler_&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;navigate&lt;/span&gt; &lt;span class="kt"&gt;About&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;h2&gt;
  
  
  Route
&lt;/h2&gt;

&lt;p&gt;This is how &lt;code&gt;Route&lt;/code&gt; is defined. It's a sum type of all possible routes in the application. The rest of this code is definition for the &lt;a href="https://github.com/natefaubion/purescript-routing-duplex"&gt;routing-duplex&lt;/a&gt; interpreter and printer. The routes can be directly written as strings but safety with types is what I prefer; &lt;a href="https://pursuit.purescript.org/packages/purescript-routing/9.0.0"&gt;routing&lt;/a&gt; and &lt;a href="https://github.com/natefaubion/purescript-routing-duplex"&gt;routing-duplex&lt;/a&gt; provide that for me.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Service.Route&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Prelude&lt;/span&gt; &lt;span class="k"&gt;hiding&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;-- Generic&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Data.Generic.Rep&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Generic&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Data.Generic.Rep.Show&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;genericShow&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Routing&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Duplex&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Duplex.Generic&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Duplex.Generic.Syntax&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&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;-- All possible routes in the application&lt;/span&gt;
&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt;
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Home&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;About&lt;/span&gt;

&lt;span class="n"&gt;derive&lt;/span&gt; &lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;genericRoute&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Generic&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt;
&lt;span class="n"&gt;derive&lt;/span&gt; &lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;eqRoute&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Eq&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt;
&lt;span class="n"&gt;derive&lt;/span&gt; &lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;ordRoute&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Ord&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt;

&lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;showRoute&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Show&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genericShow&lt;/span&gt;

&lt;span class="n"&gt;routeCodec&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;RouteDuplex'&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt;
&lt;span class="n"&gt;routeCodec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Home"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;noArgs&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"About"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"about"&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;noArgs&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Page
&lt;/h2&gt;

&lt;p&gt;The page components are defined &lt;a href="https://www.taezos.org/piq9117/notes-examples/src/branch/master/react-context-router/src/Page"&gt;here&lt;/a&gt;. They're trivially defined components that will display the text "Home" and "About". In a non-trivial app, these would be the components that will encapsulate an entire page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Route Store
&lt;/h2&gt;

&lt;p&gt;This is the component that will watch the route changes. Everytime the hash route changes, it will run &lt;code&gt;setRoute&lt;/code&gt; and updates the &lt;code&gt;Route&lt;/code&gt;. This component will then pass it on to its &lt;code&gt;content&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Component.Store&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Prelude&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Data.Maybe&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&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;-- Internal Service&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Service.Route&lt;/span&gt;
&lt;span class="c1"&gt;-- Effect&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Routing&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Hash&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;matchesWith&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Duplex&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- React&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;React.Basic.Hooks&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;ReactComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;ReactContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;/\&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kt"&gt;JSX&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;React.Basic.Hooks&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;React&lt;/span&gt;

&lt;span class="n"&gt;mkRouteStore&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;ReactContext&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;ReactComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Array&lt;/span&gt; &lt;span class="kt"&gt;JSX&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;mkRouteStore&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="s"&gt;"Store"&lt;/span&gt; &lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;useContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;
    &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="o"&gt;/\&lt;/span&gt; &lt;span class="n"&gt;setRoute&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;useState&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;
    &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;useEffect&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;matchesWith&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;parse&lt;/span&gt; &lt;span class="n"&gt;routeCodec&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;mOld&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;mOld&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;setRoute&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;
    &lt;span class="n"&gt;pure&lt;/span&gt;
      &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kt"&gt;React&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Navigation
&lt;/h2&gt;

&lt;p&gt;The only capability of this app is navigation, but if there are other capabilities like requesting data, logging, and authentication it will also be defined similar to this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Service.Navigate&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Prelude&lt;/span&gt;
&lt;span class="c1"&gt;-- Internal Service&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Service.Route&lt;/span&gt;
&lt;span class="c1"&gt;-- Effect&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Routing&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Duplex&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Routing.Hash&lt;/span&gt;

&lt;span class="kr"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Monad&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="kt"&gt;Navigate&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="n"&gt;navigate&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Route&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="kt"&gt;Unit&lt;/span&gt;

&lt;span class="kr"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;navigateEffect&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Navigate&lt;/span&gt; &lt;span class="kt"&gt;Effect&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="n"&gt;navigate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;setHash&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="n"&gt;routeCodec&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I thought this was a great article on&lt;br&gt;
&lt;a href="https://jproyo.github.io/posts/2019-03-17-tagless-final-haskell.html"&gt;tagless-final-encoding&lt;/a&gt;. This is the technique being used here. Code re-use can be easier achieved with this technique because I don't have to change big chunks of the app if I need to implement it in another context. This app runs on &lt;code&gt;Effect&lt;/code&gt; so I only have to define an instance for that. If the application needs to run on &lt;code&gt;Aff&lt;/code&gt; then I'll define a new instance for &lt;code&gt;Aff&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;React runs on &lt;code&gt;Effect&lt;/code&gt; so that's why I've defined an &lt;code&gt;Effect&lt;/code&gt; instance.&lt;/p&gt;
&lt;h2&gt;
  
  
  Main
&lt;/h2&gt;

&lt;p&gt;Finally, the &lt;code&gt;Main&lt;/code&gt; module. This is where purescript-react-basic-hooks runs application. Nothing really special, it looks for an element with &lt;code&gt;id&lt;/code&gt; of &lt;code&gt;app&lt;/code&gt; then appends the application to that DOM node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Main&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Prelude&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Data.Maybe&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&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;-- Web&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Web.DOM.NonElementParentNode&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;getElementById&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Web.HTML.HTMLDocument&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;toNonElementParentNode&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Web.HTML.Window&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;document&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Web.HTML&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;window&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Internal&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Component.Router&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Router&lt;/span&gt;
&lt;span class="c1"&gt;-- Effect&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Effect.Exception&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;throw&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- React&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;React.Basic.Hooks&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;element&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;React.Basic.DOM&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;R&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Effect&lt;/span&gt; &lt;span class="kt"&gt;Unit&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;mApp&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;getElementById&lt;/span&gt; &lt;span class="s"&gt;"app"&lt;/span&gt; &lt;span class="o"&gt;=&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="n"&gt;toNonElementParentNode&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;mApp&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
    &lt;span class="kt"&gt;Nothing&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;throw&lt;/span&gt; &lt;span class="s"&gt;"App element not found."&lt;/span&gt;
    &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;mainComponent&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kt"&gt;Router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkComponent&lt;/span&gt;
      &lt;span class="kt"&gt;R&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="n"&gt;mainComponent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/thomashoneyman/purescript-halogen-realworld"&gt;Purescript Halogen Realworld&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pursuit.purescript.org/packages/purescript-react-basic-hooks/4.2.2"&gt;React Basic Hooks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/natefaubion/purescript-routing-duplex"&gt;Routing Duplex&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pursuit.purescript.org/packages/purescript-routing/9.0.0"&gt;Routing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jproyo.github.io/posts/2019-03-17-tagless-final-haskell.html"&gt;Tagless Final Encoding by Juan Pablo Royo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://serokell.io/blog/tagless-final"&gt;Introduction to Tagless Final by Serokell&lt;/a&gt;&lt;/p&gt;

</description>
      <category>purescript</category>
      <category>routing</category>
      <category>react</category>
    </item>
    <item>
      <title>Purescript - React Basic Hooks, useAff</title>
      <dc:creator>Ken Aguilar</dc:creator>
      <pubDate>Thu, 27 Feb 2020 18:33:14 +0000</pubDate>
      <link>https://dev.to/piq9117/purescript-react-basic-hooks-useaff-55lc</link>
      <guid>https://dev.to/piq9117/purescript-react-basic-hooks-useaff-55lc</guid>
      <description>&lt;p&gt;According to the &lt;a href="https://pursuit.purescript.org/packages/purescript-react-basic-hooks/4.2.1/docs/React.Basic.Hooks.Aff#v:useAff"&gt;documentation&lt;/a&gt;, &lt;code&gt;useAff&lt;/code&gt; is defined like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;useAff&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;Eq&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Aff&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Hook&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UseAff&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Result&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Aff&lt;/code&gt; is used for asynchronous effects. The &lt;a href="https://pursuit.purescript.org/packages/purescript-aff/5.1.2"&gt;docs&lt;/a&gt; on &lt;code&gt;Aff&lt;/code&gt; is a great place to learn about it!&lt;/p&gt;

&lt;p&gt;Back to &lt;code&gt;useAff&lt;/code&gt;, when I first encountered this function I didn't&lt;br&gt;
really know what it does. Sure, the type signature gave me some clues, like I need to give me it some &lt;code&gt;key&lt;/code&gt; with the condition that this key has to have an &lt;code&gt;Eq&lt;/code&gt; instance. The second parameter needs an &lt;code&gt;Aff&lt;/code&gt;, then it will return some type &lt;a href="https://pursuit.purescript.org/packages/purescript-react-basic-hooks/4.2.1/docs/React.Basic.Hooks.Internal#t:Hook"&gt;&lt;code&gt;Hook&lt;/code&gt;&lt;/a&gt;. Based on the second parameter this tells me that this is the function I need to make asynchronous effects.&lt;/p&gt;

&lt;p&gt;This is my &lt;a href="https://taezos.org/piq9117/notes-examples/src/branch/master/spago-react-hooks-login/src/Component/LoginAff.purs#L23"&gt;login component&lt;/a&gt; using &lt;code&gt;useAff&lt;/code&gt; but it didn't start out like this. My first implementation for &lt;code&gt;useAff&lt;/code&gt; was something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;useAff&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;submitLogin&lt;/span&gt; &lt;span class="n"&gt;isSubmitting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I was very confused on why it's only getting called once after render. I also&lt;br&gt;
tried something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;useAff&lt;/span&gt; &lt;span class="s"&gt;"pleaseWork"&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;submitLogin&lt;/span&gt; &lt;span class="n"&gt;isSubmitting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Of course that didn't work. &lt;/p&gt;

&lt;p&gt;I kept going back to this &lt;a href="https://github.com/spicydonuts/purescript-react-basic-hooks/blob/master/examples/aff/src/AffEx.purs#L75"&gt;example&lt;/a&gt; and this &lt;a href="https://github.com/piq9117/purescript-react-basic-dogs"&gt;repo&lt;/a&gt;, and kept wondering what I'm doing different. Then I had my "eureka" moment. I said to myself, "Maybe the &lt;code&gt;Eq&lt;/code&gt; constraint has something to do with it. Maybe it checks the equality of the &lt;code&gt;key&lt;/code&gt; parameter I passed in, and if it changes something will happen?" So I changed my implementation to this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;useAff&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;submitLogin&lt;/span&gt; &lt;span class="n"&gt;isSubmitting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;login&lt;/code&gt; changes when the button is clicked on this &lt;a href="https://taezos.org/piq9117/notes-examples/src/branch/master/spago-react-hooks-login/src/Component/LoginAff.purs#L46"&gt;line&lt;/a&gt;.&lt;br&gt;
It worked!&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://pursuit.purescript.org/packages/purescript-react-basic-hooks/4.2.1"&gt;Purescript React Basic Hooks Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/spicydonuts/purescript-react-basic-hooks/tree/master/examples"&gt;Purescript React Basic Hooks Examples&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/piq9117/purescript-react-basic-dogs"&gt;Purescript React Basic Dogs repo by Peter Murphy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pursuit.purescript.org/packages/purescript-aff/5.1.2"&gt;Purescript Aff Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/milesfrain"&gt;Miles Frain&lt;/a&gt; for answering my questions in fpchat&lt;/p&gt;

</description>
      <category>purescript</category>
      <category>react</category>
      <category>functionalprograming</category>
    </item>
    <item>
      <title>Typescript - Manipulating Deeply Nested Immutable Objects with Lenses</title>
      <dc:creator>Ken Aguilar</dc:creator>
      <pubDate>Wed, 29 Jan 2020 22:46:42 +0000</pubDate>
      <link>https://dev.to/piq9117/typescript-manipulating-deeply-nested-immutable-objects-with-lenses-28oh</link>
      <guid>https://dev.to/piq9117/typescript-manipulating-deeply-nested-immutable-objects-with-lenses-28oh</guid>
      <description>&lt;p&gt;Javascript doesn't really have an immutable object but with typescript I can&lt;br&gt;
prevent compilation if there's a rogue function that will try to mutate an object.&lt;/p&gt;

&lt;p&gt;Let's say I have this object, and let's assume the values are always there&lt;br&gt;
because if I start talking about the possibility of &lt;code&gt;null&lt;/code&gt; then I have to talk&lt;br&gt;
about prisms. So let's take it easy and stick with lenses for now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bankIdentity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BankIdentity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Malakoff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;NY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;street&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2992 Cameron Road&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;postal_code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;14236&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;US&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It has this type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&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;readonly&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;street&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;postal_code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AddressData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;data&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;readonly&lt;/span&gt; &lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Owner&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;readonly&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;AddressData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Owner&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;BankIdentity&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Account&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;h3&gt;
  
  
  Accessing a value
&lt;/h3&gt;

&lt;p&gt;Without using any library I can manipulate this object no problem.&lt;br&gt;
When I want to access a field, I just do the dot syntax and it gives me the&lt;br&gt;
value of that field.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cityRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nx"&gt;bankIdentity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;owner&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// "Malakoff"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting a new value and returning the whole object
&lt;/h3&gt;

&lt;p&gt;It becomes a hassle when I have to set a new value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cityRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="nx"&gt;bankIdentity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="na"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="nx"&gt;bankIdentity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;owner&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;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                    &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Another City&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// { account:&lt;/span&gt;
&lt;span class="c1"&gt;//    { owner:&lt;/span&gt;
&lt;span class="c1"&gt;//       { address:&lt;/span&gt;
&lt;span class="c1"&gt;//          { data:&lt;/span&gt;
&lt;span class="c1"&gt;//             { city: 'Another City',&lt;/span&gt;
&lt;span class="c1"&gt;//               region: 'NY',&lt;/span&gt;
&lt;span class="c1"&gt;//               street: '2992 Cameron Road',&lt;/span&gt;
&lt;span class="c1"&gt;//               postal_code: '14236',&lt;/span&gt;
&lt;span class="c1"&gt;//               country: 'US' &lt;/span&gt;
&lt;span class="c1"&gt;//             } &lt;/span&gt;
&lt;span class="c1"&gt;//         } &lt;/span&gt;
&lt;span class="c1"&gt;//      } &lt;/span&gt;
&lt;span class="c1"&gt;//  } &lt;/span&gt;
&lt;span class="c1"&gt;//}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Applying a function and returning the whole object
&lt;/h3&gt;

&lt;p&gt;Same ugliness can be seen when applying a function to the field.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;capitalize&lt;/span&gt; &lt;span class="o"&gt;=&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;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;string&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;toUpperCase&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;cityRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="nx"&gt;bankIdentity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="nx"&gt;bankIdentity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;owner&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;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;capitalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bankIdentity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;owner&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city&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="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;// { account:&lt;/span&gt;
&lt;span class="c1"&gt;//    { owner:&lt;/span&gt;
&lt;span class="c1"&gt;//       { address:&lt;/span&gt;
&lt;span class="c1"&gt;//          { data:&lt;/span&gt;
&lt;span class="c1"&gt;//             { city: 'MALAKOFF',&lt;/span&gt;
&lt;span class="c1"&gt;//               region: 'NY',&lt;/span&gt;
&lt;span class="c1"&gt;//               street: '2992 Cameron Road',&lt;/span&gt;
&lt;span class="c1"&gt;//               postal_code: '14236',&lt;/span&gt;
&lt;span class="c1"&gt;//               country: 'US' &lt;/span&gt;
&lt;span class="c1"&gt;//             } &lt;/span&gt;
&lt;span class="c1"&gt;//         } &lt;/span&gt;
&lt;span class="c1"&gt;//      } &lt;/span&gt;
&lt;span class="c1"&gt;//  } &lt;/span&gt;
&lt;span class="c1"&gt;//}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;a href="https://github.com/gcanti/monocle-ts"&gt;monocle-ts&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Lenses to the rescue! Unfortunately I don't think it's possible or at least easy&lt;br&gt;
to generate lenses based on the objects like what &lt;a href="https://hackage.haskell.org/package/lens-4.18.1/docs/Control-Lens-Combinators.html#v:makeLenses"&gt;makeLenses&lt;/a&gt; does, &lt;br&gt;
so I have to hand code all of them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&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;Lens&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;monocle-ts&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;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Lens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromProp&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Bankdentity&lt;/span&gt;&lt;span class="o"&gt;&amp;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;account&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;owner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Lens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromProp&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;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;owner&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;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Lens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromProp&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Owner&lt;/span&gt;&lt;span class="o"&gt;&amp;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;address&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Lens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromProp&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AddressData&lt;/span&gt;&lt;span class="o"&gt;&amp;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;data&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;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Lens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromProp&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="o"&gt;&amp;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;city&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;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Lens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromProp&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="o"&gt;&amp;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;region&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;street&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Lens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromProp&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="o"&gt;&amp;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;street&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;postalCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Lens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromProp&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="o"&gt;&amp;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;postal_code&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;country&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Lens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromProp&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="o"&gt;&amp;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;country&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;Well... accessing a value with monocle-ts looks pretty verbose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cityRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compose&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="nx"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bankIdentity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// "Malakoff"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I guess I can do it like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cityRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Lens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromPath&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BankIdentity&lt;/span&gt;&lt;span class="o"&gt;&amp;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;account&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;owner&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;address&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;data&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;city&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bankIdentity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// "Malakoff"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;but I think it's better to just use the dot syntax, at least in my opinion.&lt;/p&gt;

&lt;p&gt;Lenses shine when it comes to updating and applying a function to a deeply&lt;br&gt;
nested value.&lt;/p&gt;
&lt;h3&gt;
  
  
  Setting a value and returning the whole object
&lt;/h3&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cityRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compose&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="nx"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Another City&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;bankIdentity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// { account:&lt;/span&gt;
&lt;span class="c1"&gt;//    { owner:&lt;/span&gt;
&lt;span class="c1"&gt;//       { address:&lt;/span&gt;
&lt;span class="c1"&gt;//          { data:&lt;/span&gt;
&lt;span class="c1"&gt;//             { city: 'Another City',&lt;/span&gt;
&lt;span class="c1"&gt;//               region: 'NY',&lt;/span&gt;
&lt;span class="c1"&gt;//               street: '2992 Cameron Road',&lt;/span&gt;
&lt;span class="c1"&gt;//               postal_code: '14236',&lt;/span&gt;
&lt;span class="c1"&gt;//               country: 'US' &lt;/span&gt;
&lt;span class="c1"&gt;//             } &lt;/span&gt;
&lt;span class="c1"&gt;//         } &lt;/span&gt;
&lt;span class="c1"&gt;//      } &lt;/span&gt;
&lt;span class="c1"&gt;//  } &lt;/span&gt;
&lt;span class="c1"&gt;//}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;I think that looks a lot cleaner than using &lt;code&gt;Object.assign&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Applying a function and returning the whole object
&lt;/h3&gt;

&lt;p&gt;Yep. That definitely looks a lot cleaner.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;capitalize&lt;/span&gt; &lt;span class="o"&gt;=&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;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;string&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;toUpperCase&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;cityRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compose&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="nx"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;modify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;capitalize&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;bankIdentity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// { account:&lt;/span&gt;
&lt;span class="c1"&gt;//    { owner:&lt;/span&gt;
&lt;span class="c1"&gt;//       { address:&lt;/span&gt;
&lt;span class="c1"&gt;//          { data:&lt;/span&gt;
&lt;span class="c1"&gt;//             { city: 'MALAKOFF',&lt;/span&gt;
&lt;span class="c1"&gt;//               region: 'NY',&lt;/span&gt;
&lt;span class="c1"&gt;//               street: '2992 Cameron Road',&lt;/span&gt;
&lt;span class="c1"&gt;//               postal_code: '14236',&lt;/span&gt;
&lt;span class="c1"&gt;//               country: 'US' &lt;/span&gt;
&lt;span class="c1"&gt;//             } &lt;/span&gt;
&lt;span class="c1"&gt;//         } &lt;/span&gt;
&lt;span class="c1"&gt;//      } &lt;/span&gt;
&lt;span class="c1"&gt;//  } &lt;/span&gt;
&lt;span class="c1"&gt;//}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://leanpub.com/optics-by-example"&gt;Optics by Example by Chris Penner&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/gcanti/monocle-ts"&gt;monocle-ts&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>typescript</category>
      <category>lenses</category>
      <category>functional</category>
    </item>
    <item>
      <title>Haskell - My Setup/Workflow</title>
      <dc:creator>Ken Aguilar</dc:creator>
      <pubDate>Tue, 26 Nov 2019 07:31:48 +0000</pubDate>
      <link>https://dev.to/piq9117/haskell-my-setup-workflow-2np2</link>
      <guid>https://dev.to/piq9117/haskell-my-setup-workflow-2np2</guid>
      <description>&lt;p&gt;Tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/ndmitchell/ghcid" rel="noopener noreferrer"&gt;ghcid&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/hlissner/doom-emacs" rel="noopener noreferrer"&gt;doom-emacs&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/jaspervdj/stylish-haskell" rel="noopener noreferrer"&gt;stylish-haskell&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.haskell.org/cabal/" rel="noopener noreferrer"&gt;cabal&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.haskellstack.org/en/stable/README/" rel="noopener noreferrer"&gt;stack&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/NixOS/nixpkgs" rel="noopener noreferrer"&gt;nixpkgs&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My setup matches my personality and that is I always go for the simplest solution. I download all these tools using &lt;a href="https://github.com/NixOS/nixpkgs" rel="noopener noreferrer"&gt;nixpkgs&lt;/a&gt; and I enable haskell-mode in &lt;a href="https://github.com/hlissner/doom-emacs" rel="noopener noreferrer"&gt;doom-emacs&lt;/a&gt;. That's it! I start writing Haskell. &lt;/p&gt;

&lt;p&gt;This is how my development workspace looks like.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F12651509%2F73392856-3b945980-42a0-11ea-99e3-fcdfdfac0229.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%2Fuser-images.githubusercontent.com%2F12651509%2F73392856-3b945980-42a0-11ea-99e3-fcdfdfac0229.png" alt="workspace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once I start writing Haskell I have another terminal open that runs &lt;a href="https://github.com/ndmitchell/ghcid" rel="noopener noreferrer"&gt;ghcid&lt;/a&gt;. It has very fast development feedback loop, it's how I know if my types are matching. I use &lt;a href="https://downloads.haskell.org/~ghc/7.10.1/docs/html/users_guide/typed-holes.html" rel="noopener noreferrer"&gt;typed-holes&lt;/a&gt; heavily so ghcid can tell me what types I need for a section of my code.&lt;/p&gt;

&lt;p&gt;Here's a contrived example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Integer&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Integer&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Integer&lt;/span&gt;
&lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;_whatdo&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will be ghcid's response in the repl&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;interactive&amp;gt;:3:13: error:
    • Found hole: _what :: Integer -&amp;gt; Integer -&amp;gt; Integer
      Or perhaps ‘_what’ is mis-spelled, or not &lt;span class="k"&gt;in &lt;/span&gt;scope
    • In the expression: _what
      In the expression: x &lt;span class="sb"&gt;`&lt;/span&gt;_what&lt;span class="sb"&gt;`&lt;/span&gt; y
      In an equation &lt;span class="k"&gt;for&lt;/span&gt; ‘add’: add x y &lt;span class="o"&gt;=&lt;/span&gt; x &lt;span class="sb"&gt;`&lt;/span&gt;_what&lt;span class="sb"&gt;`&lt;/span&gt; y
    • Relevant bindings include
        y :: Integer &lt;span class="o"&gt;(&lt;/span&gt;bound at &amp;lt;interactive&amp;gt;:3:7&lt;span class="o"&gt;)&lt;/span&gt;
        x :: Integer &lt;span class="o"&gt;(&lt;/span&gt;bound at &amp;lt;interactive&amp;gt;:3:5&lt;span class="o"&gt;)&lt;/span&gt;
        add :: Integer -&amp;gt; Integer -&amp;gt; Integer &lt;span class="o"&gt;(&lt;/span&gt;bound at &amp;lt;interactive&amp;gt;:3:1&lt;span class="o"&gt;)&lt;/span&gt;
      Valid hole fits include
        add :: Integer -&amp;gt; Integer -&amp;gt; Integer &lt;span class="o"&gt;(&lt;/span&gt;bound at &amp;lt;interactive&amp;gt;:3:1&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;seq&lt;/span&gt; :: forall a b. a -&amp;gt; b -&amp;gt; b
          with &lt;span class="nb"&gt;seq&lt;/span&gt; @Integer @Integer
          &lt;span class="o"&gt;(&lt;/span&gt;imported from ‘Prelude’
           &lt;span class="o"&gt;(&lt;/span&gt;and originally defined &lt;span class="k"&gt;in&lt;/span&gt; ‘ghc-prim-0.5.3:GHC.Prim’&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;(&lt;/span&gt;-&lt;span class="o"&gt;)&lt;/span&gt; :: forall a. Num a &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; a -&amp;gt; a -&amp;gt; a
          with &lt;span class="o"&gt;(&lt;/span&gt;-&lt;span class="o"&gt;)&lt;/span&gt; @Integer
          &lt;span class="o"&gt;(&lt;/span&gt;imported from ‘Prelude’ &lt;span class="o"&gt;(&lt;/span&gt;and originally defined &lt;span class="k"&gt;in&lt;/span&gt; ‘GHC.Num’&lt;span class="o"&gt;))&lt;/span&gt;
        asTypeOf :: forall a. a -&amp;gt; a -&amp;gt; a
          with asTypeOf @Integer
          &lt;span class="o"&gt;(&lt;/span&gt;imported from ‘Prelude’ &lt;span class="o"&gt;(&lt;/span&gt;and originally defined &lt;span class="k"&gt;in&lt;/span&gt; ‘GHC.Base’&lt;span class="o"&gt;))&lt;/span&gt;
        const :: forall a b. a -&amp;gt; b -&amp;gt; a
          with const @Integer @Integer
          &lt;span class="o"&gt;(&lt;/span&gt;imported from ‘Prelude’ &lt;span class="o"&gt;(&lt;/span&gt;and originally defined &lt;span class="k"&gt;in&lt;/span&gt; ‘GHC.Base’&lt;span class="o"&gt;))&lt;/span&gt;
        max :: forall a. Ord a &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; a -&amp;gt; a -&amp;gt; a
          with max @Integer
          &lt;span class="o"&gt;(&lt;/span&gt;imported from ‘Prelude’
           &lt;span class="o"&gt;(&lt;/span&gt;and originally defined &lt;span class="k"&gt;in&lt;/span&gt; ‘ghc-prim-0.5.3:GHC.Classes’&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;(&lt;/span&gt;Some hole fits suppressed&lt;span class="p"&gt;;&lt;/span&gt; use &lt;span class="nt"&gt;-fmax-valid-hole-fits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;N or &lt;span class="nt"&gt;-fno-max-valid-hole-fits&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells me that I need a function that takes two &lt;code&gt;Integer&lt;/code&gt; that also outputs an &lt;code&gt;Integer&lt;/code&gt;. This even tells me the "Relevant bindings" and "Valid hole fits" which is amazing. ghcid helps as much as it can. This flow goes a very long way. It starts getting hazy for me when it comes to &lt;a href="https://www.stackage.org/lts-14.16/package/lens-4.17.1" rel="noopener noreferrer"&gt;lens&lt;/a&gt; errors, but I'm sure if I use lens more often I'll be able to decipher what ghcid is telling me much quickly. This even works in the type level.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;_whatdo&lt;/span&gt;
&lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ghcid repl will respond with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;interactive&amp;gt;:8:1: error:
    • Couldn&lt;span class="s1"&gt;'t match expected type ‘_whatdo’
                  with actual type ‘Integer -&amp;gt; Integer -&amp;gt; Integer’
      ‘_whatdo’ is a rigid type variable bound by
        the type signature for:
          add :: forall _whatdo. _whatdo
        at &amp;lt;interactive&amp;gt;:7:1-14
    • The equation(s) for ‘add’ have two arguments,
      but its type ‘_whatdo’ has none
    • Relevant bindings include
        add :: _whatdo (bound at &amp;lt;interactive&amp;gt;:8:1)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ghcid is the reason I don't use any IDE or any fancy editor plugins. I only have syntax highlighting and some formatting in my emacs.&lt;/p&gt;

&lt;p&gt;When it comes to actually running my code I usually use &lt;a href="https://www.haskell.org/cabal/" rel="noopener noreferrer"&gt;cabal&lt;/a&gt;. After ghcid tells me my code is clear I run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cabal new-build
cabal new-run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sometimes I use &lt;a href="https://docs.haskellstack.org/en/stable/README/" rel="noopener noreferrer"&gt;stack&lt;/a&gt; because of &lt;a href="https://github.com/yesodweb/yesod" rel="noopener noreferrer"&gt;yesod&lt;/a&gt;. That's mostly for work.&lt;/p&gt;

&lt;p&gt;I'm aware of the holy war between stack, cabal, and nix, I hope this blog doesn't get involved in that war. I use all of them. They all have a spot in my workflow.&lt;/p&gt;

</description>
      <category>haskell</category>
      <category>functional</category>
    </item>
  </channel>
</rss>
