<?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>Forem: Peter Szerzo</title>
    <description>The latest articles on Forem by Peter Szerzo (@peterszerzo).</description>
    <link>https://forem.com/peterszerzo</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%2F197308%2F04693e03-27db-4214-af6a-17b08e58442c.png</url>
      <title>Forem: Peter Szerzo</title>
      <link>https://forem.com/peterszerzo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/peterszerzo"/>
    <language>en</language>
    <item>
      <title>My year on the frontend, 2020 edition</title>
      <dc:creator>Peter Szerzo</dc:creator>
      <pubDate>Mon, 28 Dec 2020 13:27:04 +0000</pubDate>
      <link>https://forem.com/peterszerzo/my-year-on-the-frontend-2020-edition-1fpk</link>
      <guid>https://forem.com/peterszerzo/my-year-on-the-frontend-2020-edition-1fpk</guid>
      <description>&lt;p&gt;My, oh my, what a year. Lockdown or no lockdown, the terminal blinked and the projects came and went, clocking in at the following stats for the year:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ongoing maintenance of 5 reasonably complicated apps ranging between 15k and 75k lines. Hi there, &lt;a href="https://nlx.ai/studio"&gt;NLX Studio&lt;/a&gt;!&lt;/li&gt;
&lt;li&gt;4 marketing sites, with the lovely &lt;a href="https://voicecompass.ai/"&gt;voicecompass.ai&lt;/a&gt; coming in last.&lt;/li&gt;
&lt;li&gt;one reasonably complicated backend.&lt;/li&gt;
&lt;li&gt;one Figma plugin (fun!!).&lt;/li&gt;
&lt;li&gt;around 15 or so quick interactive prototypes for clients.&lt;/li&gt;
&lt;li&gt;one 3d app plus a &lt;a href="https://splytlight.surge.sh/"&gt;3d pet project&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;4 app frameworks: React, Elm, Svelte and Vue.&lt;/li&gt;
&lt;li&gt;4 styling solutions: ✨Tailwind✨, vanilla CSS4, &lt;a href="https://emotion.sh"&gt;CSS in JS&lt;/a&gt;, &lt;a href="https://package.elm-lang.org/packages/mdgriffith/elm-ui/latest/"&gt;elm-ui&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Never would I have imagined there would be so much going on, and it seems next to impossible to sort out a coherent story. Nonetheless, here is a catalog of thoughts:&lt;/p&gt;

&lt;h2&gt;
  
  
  Elm is wonderful. Elm purism isn't.
&lt;/h2&gt;

&lt;p&gt;Elm is an absolute delight of a language, bringing a strict yet friendly Haskell-like environment to the frontend. The main selling points are a bulletproof type system including type-safe IO, delightful error messages, a spotlessly designed ecosystem, and strong guarantees across the board.&lt;/p&gt;

&lt;p&gt;I got invested in Elm way before TypeScript got decent (&amp;gt; v2.6) or React came out with hooks, and for the longest time I thought the best thing was to write as much in Elm as possible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;actor model for ports that are almost always used in a request-response style? Bring it!&lt;/li&gt;
&lt;li&gt;sub-views with laborious wiring? No problem, I just use some Vim macros.&lt;/li&gt;
&lt;li&gt;no FFI, no local state, no effect modules? Thanks for looking out for me!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yet today, my idealism is crumbling. I am maintaining a 75k line Elm app with some &lt;a href="https://github.com/peterszerzo/elm-porter"&gt;straaange stuff in it&lt;/a&gt; just to keep it sane. Because of the boilerplate, I still find places where subscriptions aren't wired up at the detriment of UX, or even worse, conflict with each other. I re-wrote the dropdown and the list editor about 5 times each, still not happy with either of them.&lt;/p&gt;

&lt;p&gt;Time for a change: my next year in Elm will be one that embraces custom elements &lt;em&gt;a whole lot more&lt;/em&gt;, limiting Elm to handle sensitive logic, the simpler chunks of UI, and the crucially valuable JSON encoding/decoding. I will no longer write up &lt;a href="https://dev.to/margaretkrutikova/elm-dom-node-decoder-to-detect-click-outside-3ioh"&gt;clickaway handlers&lt;/a&gt; or set up dictionaries of dropdown UI states in Elm.&lt;/p&gt;

&lt;p&gt;Why? I lost faith that this kind of Elm purism will get me to a level of UI quality I can defend in front of project owners. React makes a painlessly reusable &lt;a href="https://dev.to/peterszerzo/generics-for-user-interfaces-hak"&gt;generic drag-and-drop list manager&lt;/a&gt; in a few dozen lines. Elm never will.&lt;/p&gt;

&lt;p&gt;The narratives of the Elm community continue to confuse me. What in the world did the 'no components' campaign even mean? Do we still advise against nesting model-view-update triplets in favor of the &lt;a href="https://github.com/evancz/elm-sortable-table"&gt;elm-sortable-table pattern&lt;/a&gt;, even though &lt;a href="https://package.elm-lang.org/packages/annaghi/dnd-list/latest/"&gt;drag and drop&lt;/a&gt; can't be set up in the latter? Are the guarantees really that strong if people can just pass in proxies and use custom elements as they please?&lt;/p&gt;

&lt;p&gt;Elm is definitely here to stay for me. However, I am hoping that a more critical and pragmatic approach to it will help me stay happy in the ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  React hooks are fantastic
&lt;/h2&gt;

&lt;p&gt;Here's a pattern I have no complaints about: good old React hooks (GORH or something?). I wrote a number of custom hooks this year including one that &lt;a href="https://www.npmjs.com/package/@nlxchat/react"&gt;fully manages a chat experience&lt;/a&gt;, and I simply can't think of a better way to package and share effectful, headless UI logic.&lt;/p&gt;

&lt;p&gt;My time spent in Elm continues to influence me in the way I write React:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I strive for a limited and (allegedly) thoughtful use of local state.&lt;/li&gt;
&lt;li&gt;no matter how good TypeScript is getting, I really miss type-safe IO the way Elm does it. I hope to use &lt;a href="https://dev.to/peterszerzo/safe-functional-io-in-typescript-an-introduction-1kmi"&gt;io-ts&lt;/a&gt; in production someday.&lt;/li&gt;
&lt;li&gt;I never got interested in projects like &lt;a href="https://github.com/immerjs/immer"&gt;immer&lt;/a&gt; and &lt;a href="https://github.com/mobxjs/mobx"&gt;MobX&lt;/a&gt; have declined even further, in favor of what I could only call 'vanilla React'. Explicitly immutable code is alright.&lt;/li&gt;
&lt;li&gt;this is not to say I have a beef with libraries now: I actually grew really fond of &lt;a href="https://formik.org/"&gt;Formik&lt;/a&gt;. It does some very thoughtful, semantically sound heavy lifting on forms.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What about Svelte and Vue?
&lt;/h2&gt;

&lt;p&gt;While I kept working on fancy(-looking) architectures in Elm and React, I also built a ton of smaller Svelte and Vue projects this year - all with satisfied owners and mostly happy users. Which got me wondering: just how much better are sites made the 'rigorous way'?&lt;/p&gt;

&lt;p&gt;Rich Harris makes the argument that terse code is good on account of research that shows (paraphrasing here):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;bugs/lines of code&lt;/code&gt; ratio of software projects is more or less constant.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is something I didn't think I would pay any attention to, but then here I am, staring at it with curious eyes.&lt;/p&gt;

&lt;p&gt;Truth is, Svelte is just very promising right now. I can implement features in no time, the HTML templates are - regardless of how long they it takes me to warm up to them - amazing for dev speed. Best of all, the API is impressively comprehensive (springs even!!) and yet with such a tiny and well-designed total surface.&lt;/p&gt;

&lt;p&gt;I will probably keep shying away from writing anything very complicated in it and go by the thinking of &lt;a href="https://www.swyx.io/svelte-sites-react-apps/"&gt;this excellent blog post&lt;/a&gt;. Additionally, Svelte gets bonus points for powering pretty much all my &lt;a href="http://sketches.peterszerzo.com"&gt;creative programming&lt;/a&gt; these days.&lt;/p&gt;

&lt;p&gt;As for Vue, which I never really liked for reasons that are outside the scope of this post to explain, things might be turning around. With the community slowly upgrading to Vue 3 (including a faithful port of React hooks and proper TypeScript support), I might just wind up writing more of it myself. Let's see, let's see.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hype I still don't buy
&lt;/h2&gt;

&lt;p&gt;This year I fully stopped listening to people preaching vanilla JavaScript or out on a bundle-shaming crusade. I refuse to apologize for shipping 100 kilobytes of &lt;code&gt;react-dom&lt;/code&gt; if it means I get to avoid hacking a static site with &lt;code&gt;document.querySelector&lt;/code&gt; (I happen to have a site that does that and it literally keeps me up at night).&lt;/p&gt;

&lt;p&gt;I am happy to talk about bundle sizes, loading times and the challenges of SSR-hydration as UX issues, as long as we keep in mind that the worst UX issue is and forever will be [drumrolls] [drumrolls] a runtime error. You know, the one caused by a haphazard architecture.&lt;/p&gt;

&lt;p&gt;I should mention that more formalized alternatives like &lt;a href="https://github.com/alpinejs/alpine/"&gt;Alpine.js&lt;/a&gt; or &lt;a href="https://hotwire.dev/"&gt;Hotwire&lt;/a&gt; do look very promising, hopefully I will get the chance to engage with them in production soon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Onwards to 2021
&lt;/h2&gt;

&lt;p&gt;I really look forward to this next year. I wonder if I will stay a Vim user in twelve months, what my next terminal color scheme will be, whether there is going to be another super cool 3d project in store for me, and how much of the thoughts and rambles above will still hold. Look forward to writing it all up again in one year's time.&lt;/p&gt;

&lt;p&gt;🍾Happy New Year🍾 everybody!&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>react</category>
      <category>elm</category>
      <category>svelte</category>
    </item>
    <item>
      <title>Generics for user interfaces</title>
      <dc:creator>Peter Szerzo</dc:creator>
      <pubDate>Wed, 14 Oct 2020 15:32:16 +0000</pubDate>
      <link>https://forem.com/peterszerzo/generics-for-user-interfaces-hak</link>
      <guid>https://forem.com/peterszerzo/generics-for-user-interfaces-hak</guid>
      <description>&lt;p&gt;How often do we write code that manages a list of a certain resource? Despite how common this comes up, I often struggled to find good patterns for setting up dozens of them in the same codebase - manage the recipes, the team members, the invoices - without too much repetition. Recently, I took a hint from TypeScript to set up something in React that I was finally happy with.&lt;/p&gt;

&lt;p&gt;Basically, if TypeScript is good at handling this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Recipe&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;description&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Recipes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Recipe&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then a TypeScript-friendly frontend framework like React could surely do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// We get to RecipeEditorProps later in the post&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;RecipeEditor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RecipeEditorProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* TBA */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;RecipeListEditor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RecipeListEditorProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Some abstraction involving &amp;lt;RecipeEditor/&amp;gt; */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&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;&lt;strong&gt;tldr&lt;/strong&gt; for those who would just like to see the thing, &lt;a href="https://codesandbox.io/s/generic-list-manager-up6nr?file=/src/App.tsx"&gt;here is a CodeSandbox&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What is a sensible abstraction that takes a component responsible for a resource and turning it into a component that handles a list of them? For lack of a better word, I am going to call it a generic UI - one that works on structures comprised of a certain unspecified type of, well, thing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;FP enthusiasts might get excited about fancier names like functor UIs or UI lifting, but I will hold off on those for the time being.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A recipe editor
&lt;/h2&gt;

&lt;p&gt;A component that is responsible for editing a recipe might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;RecipeEditorProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Recipe&lt;/span&gt;
  &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newRecipe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Recipe&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;RecipeEditor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RecipeEditorProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&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;input&lt;/span&gt;
      &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&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;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="na"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="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;onChange&lt;/span&gt;&lt;span class="p"&gt;({&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;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
        &lt;span class="p"&gt;});&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="nx"&gt;input&lt;/span&gt;
      &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&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;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="na"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="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;onChange&lt;/span&gt;&lt;span class="p"&gt;({&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;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
        &lt;span class="p"&gt;});&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="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;a href="https://reactjs.org/docs/forms.html#controlled-components"&gt;controlled component&lt;/a&gt; allows its parent to manage the resource in question so the state can be flexibly managed high enough in the component hierarchy. &lt;/p&gt;

&lt;h2&gt;
  
  
  Combining into a list
&lt;/h2&gt;

&lt;p&gt;We can build on this simple editor to create a list of them: simply map over the list of resources and wire up the change events to (immutably) update the list at the right index, with some delete buttons to top it off. I could add some code for it here, but at that point I added another React todo list tutorial onto the pile.&lt;/p&gt;

&lt;p&gt;Instead, let's look at a list manager component that doesn't care what is inside the node.&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstracting a generic list editor
&lt;/h2&gt;

&lt;p&gt;This abstract &lt;code&gt;ListEditor&lt;/code&gt; component would take the resource editor component as a prop and do the rest of the work for us. Here's some type definitions for the props of such a component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;newValues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;newValue&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;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;newValueLabel&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="nl"&gt;Editor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;EditorProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// The props for the item editor, parameterized by T&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;EditorProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, everything is parameterized by &lt;code&gt;T&lt;/code&gt;, which we can later fill in as &lt;code&gt;Recipe&lt;/code&gt;, &lt;code&gt;User&lt;/code&gt; etc. In addition to &lt;code&gt;values&lt;/code&gt; and &lt;code&gt;onChange&lt;/code&gt;, the component will also need a few peripheral props like how to create a new value when the add button is clicked, and what label said button should have.&lt;/p&gt;

&lt;p&gt;The implementation looks roughly like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;ListEditor&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&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;values&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;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Editor&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newItem&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="c1"&gt;// Use a helper to immutably change item at an index&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;onChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newItem&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;values&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
              &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Use a helper to immutably remove an item at an index&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;onChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;removeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&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;values&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              Delete
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="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;onChange&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;values&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;newValue&lt;/span&gt;&lt;span class="p"&gt;()]);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&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;newValueLabel&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Add new&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&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;We finally get the instantiate a &lt;code&gt;&amp;lt;props.Editor /&amp;gt;&lt;/code&gt; instance with the appropriate props, and add all the peripheral UI like add and delete buttons that would then look consistent wherever this component is used.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding UX goodies in peace
&lt;/h2&gt;

&lt;p&gt;Now that we have a generic list editor component, we can add fancy UX features knowing that they will propagate for every single list editor in our codebase.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://codesandbox.io/s/generic-list-manager-up6nr"&gt;CodeSandbox&lt;/a&gt;, I added &lt;code&gt;react-beautiful-dnd&lt;/code&gt; to allow simple rearranging for both the recipes list and the users list. The individual editors never found out they were being pushed around 🤓.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Jju_NjRr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1p6o9qu4mr7frwssnbk1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Jju_NjRr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1p6o9qu4mr7frwssnbk1.gif" alt="Drag and drop demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;What can we do with this? I don't think it pattern makes sense as some kind of importable package - it is still quite coupled to styled UI code, and decoupling it would lead us down the road of fancy custom hooks, more custom component props or functions-as-child. I think we will be better off just setting up these few dozen lines of code in our projects and customize it to our own needs.&lt;/p&gt;

&lt;p&gt;Perhaps more important is the general idea: components that manage a constellation of things without needing to know what the things themselves are. This kind of decoupling has saved me countless hours of maintenance work on &lt;a href="https://peterszerzo.github.io/elm-arborist/"&gt;complex projects well beyond lists&lt;/a&gt;. I hope it's useful for you as well!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>react</category>
      <category>functional</category>
      <category>generics</category>
    </item>
    <item>
      <title>Introducing Arborist, the tree editor for Elm</title>
      <dc:creator>Peter Szerzo</dc:creator>
      <pubDate>Wed, 30 Oct 2019 09:41:56 +0000</pubDate>
      <link>https://forem.com/peterszerzo/introducing-arborist-the-tree-editor-for-elm-49po</link>
      <guid>https://forem.com/peterszerzo/introducing-arborist-the-tree-editor-for-elm-49po</guid>
      <description>&lt;p&gt;Two years ago, I published the first version of &lt;a href="https://peterszerzo.github.io/elm-arborist/" rel="noopener noreferrer"&gt;elm-arborist&lt;/a&gt;, a package for editing generic tree structures in Elm. I didn't advertise it too much at the time so it quietly went through 2 major re-writes and &lt;code&gt;elm bump&lt;/code&gt;-ed all the way up to version 8.2.0. All the while, it kept supporting more and more sophisticated needs in the &lt;a href="https://nlx.ai/" rel="noopener noreferrer"&gt;NLX Studio app&lt;/a&gt;, where I use it to visually define conversational logic for chatbots.&lt;/p&gt;

&lt;p&gt;Whether you have a complex use-case or not (after all, tree structures are everywhere), the goal of the library is to make editing trees smooth, contained and flexible: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Arborist takes care of editing the structure (adding new nodes, rearranging subtrees etc.).&lt;/li&gt;
&lt;li&gt;you take care of editing the internals of each node.&lt;/li&gt;
&lt;li&gt;divide and conquer any use-case by combining the two together with minimal glue code. And since I can't help it: #functor.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We will look into how this works in this post. But first, a quick origin story.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where It All Began
&lt;/h2&gt;

&lt;p&gt;In a previous career in the architecture world, I spent a lot of time working with a tool called Grasshopper, a visual programming extension for the 3d modeling program Rhino:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/nJUq8ImJnbM"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this environment, variables are represented as sliders, connected to boxes that either did transformation on their values or used them as coordinates to draw shapes. The resulting cable salads - found in countless other tools such as &lt;a href="https://cables.gl/" rel="noopener noreferrer"&gt;cables.gl&lt;/a&gt; - were beautiful and weird and full of possibilities. Finally, the structure of the 'code' was visual in a way a static folder structure could never truthfully represent.&lt;/p&gt;

&lt;p&gt;When &lt;a href="https://nlx.ai/" rel="noopener noreferrer"&gt;NLX Studio&lt;/a&gt;, my current startup, developed a need for a tool to model conversation logic, we thought of something similar, yet simpler and easier to organize. Instead of Grasshopper's directed graph, how about a (non-binary) tree? This is what &lt;code&gt;Arborist&lt;/code&gt; wound up supporting: utilities to create a tree holding a generic data structure, a fully flexible way to render it, along with an event handling machinery allowing users to expand and alter the structure visually.&lt;/p&gt;

&lt;p&gt;Let's see how it all works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an Editable Tree
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;tldr;&lt;/strong&gt; this section runs through a &lt;a href="https://github.com/peterszerzo/elm-arborist/blob/master/examples/Simple.elm" rel="noopener noreferrer"&gt;simple Arborist example&lt;/a&gt;. Feel free to just read the example on its own.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We start by defining a &lt;code&gt;Node&lt;/code&gt; type, and build up a starting tree using the &lt;code&gt;Arborist.Tree&lt;/code&gt; module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Arborist&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Arborist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Tree&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;Tree&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;MyNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
  &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;answer&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;startingTree&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Tree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Tree&lt;/span&gt; &lt;span class="kt"&gt;Node&lt;/span&gt;
&lt;span class="n"&gt;startingTree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kt"&gt;Tree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Node&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;MyNode&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;How are you?"&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fine, thanks"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;Tree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Node&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;MyNode&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Great. Would you like coffee?"&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Absolutely"&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;We can define each tree with the &lt;code&gt;Tree.Node&lt;/code&gt; constructor that takes the root node and an array of child nodes that are of the same recursive structure.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Creating trees in Elm this way is nothing new or special. It is, in fact, a &lt;a href="https://evancz.gitbooks.io/functional-programming-in-elm/recursion/binary-trees.html" rel="noopener noreferrer"&gt;very common example&lt;/a&gt; when talking about the language's type system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next, we lay out a &lt;code&gt;Model&lt;/code&gt; that contains this tree, as well as some internal state that &lt;code&gt;Arborist&lt;/code&gt; will need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Tree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Tree&lt;/span&gt; &lt;span class="kt"&gt;MyNode&lt;/span&gt;
  &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arboristState&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Arborist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;State&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt;
&lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;startingTree&lt;/span&gt;
  &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arboristState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Arborist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The editor will need some initial settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;arboristSettings&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Arborist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Setting&lt;/span&gt; &lt;span class="kt"&gt;MyNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;arboristSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;Settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keyboardNavigation&lt;/span&gt; &lt;span class="kt"&gt;True&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;defaultNode&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;MyNode&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A"&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Q"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nodeWidth&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gutter&lt;/span&gt; &lt;span class="mi"&gt;20&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;Arborist&lt;/code&gt; will send a single message that updates the model like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Model&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;Model&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Cmd&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
        &lt;span class="kt"&gt;Arborist&lt;/span&gt; &lt;span class="n"&gt;updater&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;newState&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newTree&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                    &lt;span class="n"&gt;updater&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arborist&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tree&lt;/span&gt;
            &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
                &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;arborist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newState&lt;/span&gt;
                &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newTree&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;none&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Instead of new state and tree values, Arborist's message comes with a function that computes them based on the current values. This is set up this way in order to prevent potential frequently fired mouse events from undoing each others' changes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally, the view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Html&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;Msg&lt;/span&gt;
&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Arborist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;
        &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arboristState&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tree&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nodeView&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nodeView&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arboristSettings&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;toMsg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Arborist&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;See the &lt;a href="https://github.com/peterszerzo/elm-arborist/blob/master/examples/Simple.elm" rel="noopener noreferrer"&gt;full example&lt;/a&gt; to see how these pieces fit together exactly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Towards a Full-featured Editor
&lt;/h3&gt;

&lt;p&gt;The simple example is a few steps behind the full-featured &lt;a href="https://peterszerzo.github.io/elm-arborist/" rel="noopener noreferrer"&gt;Arborist home page example&lt;/a&gt;. Here are the most important methods from the library that will get us there:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://package.elm-lang.org/packages/peterszerzo/elm-arborist/latest/Arborist#activeNode" rel="noopener noreferrer"&gt;activeNode&lt;/a&gt; and &lt;a href="https://package.elm-lang.org/packages/peterszerzo/elm-arborist/latest/Arborist#setActiveNode" rel="noopener noreferrer"&gt;setActiveNode&lt;/a&gt;: when a tree node is focused, you can retrieve it using &lt;code&gt;activeNode&lt;/code&gt; and use it to render a piece of UI responsible for editing its internals. Use &lt;code&gt;setActiveNode&lt;/code&gt; in the update method to persist changes in the tree.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://package.elm-lang.org/packages/peterszerzo/elm-arborist/latest/Arborist#subscriptions" rel="noopener noreferrer"&gt;subscriptions&lt;/a&gt;: like the &lt;a href="https://package.elm-lang.org/packages/peterszerzo/elm-arborist/latest/Arborist#Updater" rel="noopener noreferrer"&gt;updater&lt;/a&gt; from the &lt;code&gt;update&lt;/code&gt; method above, Arborist's &lt;code&gt;subscriptions&lt;/code&gt; take a bit of type-fu to set up. In the end, though, they won't take up that much space, and add a lot of goodies like animations and keyboard navigation outlined in the remainder of this post.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;See the &lt;a href="https://github.com/peterszerzo/elm-arborist/blob/master/landing/src/Landing.elm" rel="noopener noreferrer"&gt;full example&lt;/a&gt; for details.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The UX Features that Count
&lt;/h2&gt;

&lt;p&gt;The first few versions of the package focused on making things work and making sure that the tree could be completely separated from the &lt;code&gt;Node&lt;/code&gt; data type it is used with. With &lt;code&gt;v8.0.0&lt;/code&gt;, it was UX time: making complicated trees intuitive to edit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keyboard Navigation
&lt;/h3&gt;

&lt;p&gt;Instead of laboriously panning and padding around to find nodes, trees can now be traversed using arrow keys:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F7x57ibjk7bevk33f2ljh.gif" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F7x57ibjk7bevk33f2ljh.gif" alt="Keyboard navigation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Clustering
&lt;/h3&gt;

&lt;p&gt;What I really loved in Grasshopper is that you could take a portion of a cable salad and pull it together in a single box with the appropriate number of inputs and outputs, the visual equivalent of factoring out a pure function. Arborist can do this for subtrees:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fs1ov7am14h3fabh001fb.gif" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fs1ov7am14h3fabh001fb.gif" alt="Arborist clustering"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To implement this feature, simply add the &lt;a href="https://package.elm-lang.org/packages/peterszerzo/elm-arborist/latest/Arborist-Settings#isNodeClustered" rel="noopener noreferrer"&gt;isNodeClustered&lt;/a&gt; logic in settings, 'teaching' the layout algorithm whether the subtree under a node should be hidden. Edit the corresponding flag for any given node with &lt;a href="https://package.elm-lang.org/packages/peterszerzo/elm-arborist/latest/Arborist#setActiveNode" rel="noopener noreferrer"&gt;setActiveNode&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Minimap
&lt;/h3&gt;

&lt;p&gt;The clustering feature, effective for grouping a logically coherent subtree, is not effective for making large trees easy to navigate. To cover that front, Arborist makes it easy to create synced minimaps like the ones we are used to in our IDE's:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F2tzpi1ni2gm6pd0avms7.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F2tzpi1ni2gm6pd0avms7.png" alt="Minimap in VSCode vs. Arborist"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To create a minimap in Arborist, simply re-use the arborist internal state on a new piece of &lt;code&gt;Arborist.view&lt;/code&gt; with new settings for a smaller geometry and new views for nodes. The design of this internal state makes sure that when you interact with your tree in either views, the viewport stays in sync:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fb00n78vr9mirtc1jw7lj.gif" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fb00n78vr9mirtc1jw7lj.gif" alt="Minimap sync"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Adding these goodies to the library has been very exciting - and hopefully, there is a lot more to come.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next up for Arborist
&lt;/h2&gt;

&lt;p&gt;The next steps for the library will likely focus on performance for very large trees. My workplace needs up to this point did not include trees larger than 50 nodes, but I would be curious to look for windows of optimization in the library's codebase to become a whole lot more ambitious than that.&lt;/p&gt;

&lt;p&gt;Do you have other ideas? Let me know by &lt;a href="https://github.com/peterszerzo/elm-arborist/issues" rel="noopener noreferrer"&gt;opening an issue&lt;/a&gt; or reaching out to me under &lt;a class="mentioned-user" href="https://dev.to/peterszerzo"&gt;@peterszerzo&lt;/a&gt; on Elm Slack or Twitter. Until then!&lt;/p&gt;

</description>
      <category>elm</category>
      <category>trees</category>
      <category>design</category>
      <category>api</category>
    </item>
    <item>
      <title>Rich interactive notebooks with elm-markup</title>
      <dc:creator>Peter Szerzo</dc:creator>
      <pubDate>Thu, 03 Oct 2019 15:37:01 +0000</pubDate>
      <link>https://forem.com/peterszerzo/rich-interactive-notebooks-with-elm-markup-part-1-50kb</link>
      <guid>https://forem.com/peterszerzo/rich-interactive-notebooks-with-elm-markup-part-1-50kb</guid>
      <description>&lt;p&gt;Whether it's Observable, Google Colab or Jupyter, I love interactive notebooks. If none of these names are familiar, such notebooks are documents where regular text snippets, headings etc. mingle with working code snippets. They are great communication tools and allow a kind of fluid play with code that is hard to get inside regular IDE's.&lt;/p&gt;

&lt;p&gt;I have been interested in making my own interactive notebooks for a long time not because there was anything missing in existing solutions, but because a lot of the times I find them to be too flexible: if a notebook allows its user to change everything, they can also be break its logic pretty easily and with little help towards recovery.&lt;/p&gt;

&lt;p&gt;And besides, how much effort would it take to make an interactive notebook on my own terms anyway...&lt;/p&gt;

&lt;p&gt;Well, without good crutches, probably a lot, so I didn't attempt it right until I stumbled upon a package in the Elm programming language called &lt;code&gt;elm-markup&lt;/code&gt;. Turns out, making a basic interactive notebook in it is much simpler than I had imagined: just under 200 lines and without even touching the package's more involved modules.&lt;/p&gt;

&lt;p&gt;This experiment is what brings me to writing this series of blog posts, covering a delightful journey looking at interactive notebooks using &lt;code&gt;elm-markup&lt;/code&gt;. We will start with a simple counter app, working our way up to some interactive drawings.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is &lt;code&gt;elm-markup&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;It is officially described as the &lt;em&gt;Elm-friendly markup language&lt;/em&gt;, one that brings Elm's promise of type safety and friendly error messages into the world of markup languages. Roughly speaking, I would sum it up as a kind of markup language that exposes its own internal structure (AST) so we can render it as we please: plain text, HTML, &lt;code&gt;elm-ui&lt;/code&gt;, or any other Elm value really. Spoiler: in this post, we will be turning markup into functions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;tldr&lt;/strong&gt; the full example with comments is available in &lt;a href="https://ellie-app.com/6PN39PX42YRa1"&gt;this Ellie&lt;/a&gt;. The rest of the post will go over it in detail.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A basic &lt;code&gt;elm-markup&lt;/code&gt; document
&lt;/h2&gt;

&lt;p&gt;Let's define a simple &lt;code&gt;Title&lt;/code&gt; block. This block would tell &lt;code&gt;elm-markup&lt;/code&gt; that whenever it sees this piece of text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|&amp;gt; Title
    Interactive counteradder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should render the indented text inside an &lt;code&gt;h1&lt;/code&gt; tag. The code for that would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;titleBlock&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Block&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;titleBlock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Title"&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using this block, we can create a document like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compile&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="n"&gt;identity&lt;/span&gt; &lt;span class="n"&gt;titleBlock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s"&gt;"""
|&amp;gt; Title
    Interactive counteradder
"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Rendering this into a running Elm app involves a few more steps that will become clear later in the post. If you're curious, the &lt;a href="https://package.elm-lang.org/packages/mdgriffith/elm-markup/latest/Mark#compile"&gt;package docs&lt;/a&gt; are your friends.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Adding a counter
&lt;/h2&gt;

&lt;p&gt;The second block we will define is a named counter that renders some UI and emits the updated value as a message. The markup syntax looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|&amp;gt; Counter
    name = var1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And without further ado, here is the code for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;counterBlock&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Block&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;counterBlock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Counter"&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&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="k"&gt;let&lt;/span&gt;
                &lt;span class="c1"&gt;-- This is a placeholder value&lt;/span&gt;
                &lt;span class="c1"&gt;-- We'll wire this up to proper state values in the next step&lt;/span&gt;
                &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="n"&gt;div&lt;/span&gt;
                &lt;span class="p"&gt;[]&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;(&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;"&lt;/span&gt;&lt;span class="s2"&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;button&lt;/span&gt;
                    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&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;text&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&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;onClick&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&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="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name"&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toBlock&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding interactivity
&lt;/h2&gt;

&lt;p&gt;So far, this &lt;code&gt;elm-markup&lt;/code&gt; document looks pretty static. In order to make it interactive and link counters to actual values by name, we will parse these them into functions that will allow us to inject values stored in the application model. This mind-bend is probably best illustrated by this shift in type signatures for the rendered block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- before&lt;/span&gt;
&lt;span class="n"&gt;counterBlock&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Block&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;counterBlock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;

&lt;span class="c1"&gt;-- after&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;Values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Dict&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Dict&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;

&lt;span class="n"&gt;counterBlock&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Block&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Values&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;counterBlock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is nothing inherent in &lt;code&gt;elm-markup&lt;/code&gt; that would stop us from taking this shift: if we're in charge of what value a piece of markup renders to, it might as well be a function. We can use this function to inject a dictionary of &lt;code&gt;Values&lt;/code&gt; directly from our model and wire up the &lt;code&gt;(String, Float)&lt;/code&gt; events that changes it in response to interacting with the counter buttons.&lt;/p&gt;

&lt;p&gt;Our finished counter block looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- We will use this helper throughout the rest of the example&lt;/span&gt;
&lt;span class="n"&gt;getValue&lt;/span&gt; &lt;span class="p"&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;Values&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
&lt;span class="n"&gt;getValue&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;values&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Dict&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
        &lt;span class="c1"&gt;-- Values that are not kept track of yet are assumed to be the default&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withDefault&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;


&lt;span class="n"&gt;counterBlock&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Block&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Values&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;counterBlock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Counter"&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;
                &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getValue&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;
            &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="n"&gt;div&lt;/span&gt;
                &lt;span class="p"&gt;[]&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;(&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;"&lt;/span&gt;&lt;span class="s2"&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;button&lt;/span&gt;
                    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&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;text&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&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;onClick&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&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="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name"&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toBlock&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Doing something with our values
&lt;/h2&gt;

&lt;p&gt;Now that our wiring is complete, we can simply define a &lt;code&gt;Sum&lt;/code&gt; block that works with this markup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|&amp;gt; Counter
    name = var1

|&amp;gt; Counter
    name = var2

|&amp;gt; Sum
    arg1 = var1
    arg2 = var2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this block will do is simply take the values from the two named counters, add them together, and communicate the result as &lt;code&gt;var1 + var2 == 3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The sum block implementation looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;sumBlock&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Block&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Values&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;sumBlock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sum"&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                    &lt;span class="n"&gt;getValue&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;getValue&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;
            &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="n"&gt;div&lt;/span&gt;
                &lt;span class="p"&gt;[]&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; + "&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&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;text&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;res&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="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;arg1"&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;arg2"&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toBlock&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wiring it all up
&lt;/h2&gt;

&lt;p&gt;Now that we have our blocks, we can write a method that compiles a document like this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;markup&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="n"&gt;markup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="s"&gt;"""
|&amp;gt; Title
    Interactive counteradder

|&amp;gt; Counter
    name = var1

|&amp;gt; Counter
    name = var2

|&amp;gt; Sum
    arg1 = var1
    arg2 = var2
"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiler for it would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;compileMarkup&lt;/span&gt; &lt;span class="p"&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;Result&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Values&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;compileMarkup&lt;/span&gt; &lt;span class="n"&gt;markdownBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compile&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;
            &lt;span class="n"&gt;identity&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;manyOf&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;titleBlock&lt;/span&gt;
                &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;counterBlock&lt;/span&gt;
                &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sumBlock&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;markdownBody&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
                    &lt;span class="kt"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Success&lt;/span&gt; &lt;span class="n"&gt;blocks&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                        &lt;span class="kt"&gt;Ok&lt;/span&gt;
                            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                                &lt;span class="n"&gt;div&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
                                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;
                                        &lt;span class="c1"&gt;-- Inject data into each block&lt;/span&gt;
                                        &lt;span class="c1"&gt;-- This makes them into regular `elm-html` nodes&lt;/span&gt;
                                        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                        &lt;span class="n"&gt;blocks&lt;/span&gt;
                                    &lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="p"&gt;)&lt;/span&gt;

                    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                        &lt;span class="kt"&gt;Err&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Compile error"&lt;/span&gt;
           &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, the main &lt;code&gt;model&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;view&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Values&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt;
    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SetValue&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt;
&lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
        &lt;span class="kt"&gt;SetValue&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&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;model&lt;/span&gt;
                &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                    &lt;span class="kt"&gt;Dict&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;key&lt;/span&gt;
                        &lt;span class="n"&gt;val&lt;/span&gt;
                        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt;
&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;compileMarkup&lt;/span&gt; &lt;span class="n"&gt;markup&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
        &lt;span class="c1"&gt;-- The success case yields a function that takes the current `Values` dictionary&lt;/span&gt;
        &lt;span class="kt"&gt;Ok&lt;/span&gt; &lt;span class="n"&gt;viewByData&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;viewByData&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;
                &lt;span class="c1"&gt;-- Map to the program message&lt;/span&gt;
                &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="kt"&gt;SetValue&lt;/span&gt;

        &lt;span class="kt"&gt;Err&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="n"&gt;text&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a full implementation, head to &lt;a href="https://ellie-app.com/6PN39PX42YRa1"&gt;the full example Ellie&lt;/a&gt; or &lt;a href="https://gist.github.com/peterszerzo/a93ad31977b4bc467a17eccc8382110e"&gt;the same code as a gist&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where will we go next?
&lt;/h2&gt;

&lt;p&gt;I know, I know, adding numbers is not that exciting. Eventually, we'll add sliders to make &lt;code&gt;elm-webgl&lt;/code&gt; drawings like &lt;a href="http://peterszerzo.com/sketches/envo"&gt;this one&lt;/a&gt;, interactive.&lt;/p&gt;

&lt;p&gt;Until then ☺️&lt;/p&gt;

</description>
      <category>elm</category>
      <category>markup</category>
      <category>interactive</category>
    </item>
    <item>
      <title>Safe functional IO in TypeScript: an introduction</title>
      <dc:creator>Peter Szerzo</dc:creator>
      <pubDate>Wed, 04 Sep 2019 14:42:26 +0000</pubDate>
      <link>https://forem.com/peterszerzo/safe-functional-io-in-typescript-an-introduction-1kmi</link>
      <guid>https://forem.com/peterszerzo/safe-functional-io-in-typescript-an-introduction-1kmi</guid>
      <description>&lt;p&gt;I spend most of my time programming in Elm these days, enjoying (while it lasts) type-safe IO and a rich type system that guarantee no runtime exceptions. And then, just last week, a fairly complex TypeScript project landed in my lap. Excited and optimistic, I spent some time looking into offering the same guarantees on this new terrain using the lovely &lt;a href="https://github.com/gcanti/io-ts"&gt;io-ts&lt;/a&gt; and &lt;a href="https://github.com/gcanti/fp-ts"&gt;fp-ts&lt;/a&gt; packages.&lt;/p&gt;

&lt;p&gt;This series sums up this learning journey, and goes by the name &lt;em&gt;Safe Functional IO in TypeScript&lt;/em&gt;. It starts out with some pain points of my previous TypeScript experience, and hopefully lands someplace nice.&lt;/p&gt;

&lt;h2&gt;
  
  
  The need for safe IO
&lt;/h2&gt;

&lt;p&gt;TypeScript's type system has gotten so good that around v3.1 and upwards, I felt comfortable making surgical changes to a 3000 loc React app relying on just the compiler and a few dozen unit tests. However, that kind of benefit only worked as long as data coming into the application behaved as I assumed it to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Fruit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&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="nl"&gt;sweetness&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="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://some.endpoint/fruit.json&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="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Fruit&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="c1"&gt;// do something with `fruit`&lt;/span&gt;
    &lt;span class="c1"&gt;// although I'm a bit worried 😨&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Guaranteeing that &lt;code&gt;fruit&lt;/code&gt; is of the right shape when comes back from the server is tricky, especially since it's tempting to trust the backend team's documentation, annotate UI code like in the snippet above and move on.&lt;/p&gt;

&lt;p&gt;But then, there is the inevitable miscommunication, mismatched versions of deployments, unpredictable caching, and the resulting bug does what bugs do best: hit hard and deliver a kind of message/stack trace that does little to narrow down its location.&lt;/p&gt;

&lt;p&gt;Not for me, and not for the users of this next product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter &lt;code&gt;io-ts&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This clever package exposes a language to define the &lt;code&gt;Fruit&lt;/code&gt; interface above in a way that surfaces not only a static type, but also a highly graceful runtime validator. For our example, it would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;t&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;io-ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Validator object, called `codec`&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Fruit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;t&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="na"&gt;sweetness&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;t&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="c1"&gt;// Static type, constructed from the codec&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Fruit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TypeOf&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;Fruit&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a bit of advanced TypeScript sorcery going on here, but for now, it suffices to know that we have a static &lt;code&gt;Fruit&lt;/code&gt; type that behaves the same as the simple interface from before. And with the &lt;code&gt;Fruit&lt;/code&gt; object, we can do our validation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Instead of the optimistic `Fruit`, we can now properly annotate as `unknown`&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;someValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sweetness&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;somewhat&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;validatedApple&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Fruit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;validatedApple&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What comes out in the console is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"_tag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Right"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"right"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"apple"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sweetness"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"somewhat"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks like the object is trying to tell me, somewhat awkwardly and with lots of repetition, that something was right. But are we really expected to work with this?&lt;/p&gt;

&lt;p&gt;Yes we do, but with lots of elegant help and definitely no &lt;code&gt;response._tag === "Right"&lt;/code&gt; checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter &lt;code&gt;fp-ts&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;io-ts&lt;/code&gt; works with the data structures of general-purpose functional programming toolkit called &lt;code&gt;fp-ts&lt;/code&gt;, both internally and in its public API. Using the package, the object above can be constructed like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;either&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/either&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;validationFromBefore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;either&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sweetness&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;somewhat&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;And if we were to annotate it, it would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;either&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Either&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Fruit&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Either&lt;/code&gt; represents a type that can go down two roads: the left, parameterized by one given type, and the right, parameterized by another. Either a folder with documents in it, or a basket with apples in it: there is always a container, and rest assured there won't be any flattened apples in that folder.&lt;/p&gt;

&lt;p&gt;To make things a bit more concrete, the left side usually holds some error (&lt;code&gt;t.Errors&lt;/code&gt; in our case), while the right some payload resulting from a successful operation (&lt;code&gt;Fruit&lt;/code&gt;). In a friendlier worded language like Elm, the either-left-right triad is called result-err-ok.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Either&lt;/code&gt; uses &lt;a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions"&gt;discriminated unions&lt;/a&gt; in TypeScript so that the compiler can help us use these containers and values correctly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Working with &lt;code&gt;Either&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;As I promised earlier, &lt;code&gt;fp-ts&lt;/code&gt; exposes some convenience functions to work with &lt;code&gt;Either&lt;/code&gt; values comfortably. To turn the decoded result into a friendly string to display in a UI, we can use a single &lt;code&gt;either.fold&lt;/code&gt; function that additionally takes two functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;onLeft&lt;/code&gt;: a function that turns the error into string&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onRight&lt;/code&gt;: a function that turns the successfully decoded fruit into a string&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In essence, the compiler simply forces us to handle both success and error cases before it lets us interact with our program. In our case, it would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;t&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;io-ts/lib/either&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;either&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/either&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Decode an arbitrary value&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Fruit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sweetness&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;somewhat&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;result&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;=&lt;/span&gt; &lt;span class="nx"&gt;either&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Something went wrong&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="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Fruit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; ~ &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sweetness&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; sweet`&lt;/span&gt;
&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Logs "apple ~ somewhat sweet"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we replace the value in the &lt;code&gt;sweetness&lt;/code&gt; field with 65 (reasonably assuming that sweetness should go on a 0-100 scale), the validation would fail and you would get &lt;code&gt;"Something went wrong"&lt;/code&gt; instead, as expected.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I set up a &lt;a href="https://codesandbox.io/s/hello-io-ts-hju9u"&gt;CodeSandbox&lt;/a&gt; containing some of this code. Feel free to play around with validations there. It is somewhat in flux and may contain all kinds of other goodies by the time you get to it, but isn't it more fun that way 🤓.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this post, I went through how make sure that a random value in TypeScript conforms to a static interface using the &lt;code&gt;io-ts&lt;/code&gt; package, and how to work with the resulting safe value afterwards using &lt;code&gt;fp-ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next up, I will set up a small app that talks to a mock server and handles all the errors. There will be some state modeling in &lt;code&gt;fp-ts&lt;/code&gt;, with more functional tricks to enjoy. Until then!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>elm</category>
      <category>functional</category>
      <category>io</category>
    </item>
  </channel>
</rss>
